我看到了以下question,我问自己是否有更好的方法来解决这个问题,所以不需要演员。 请考虑以下代码:
#include <iostream>
class Base
{
public:
virtual ~Base() {}
};
class Derived : public Base
{
protected:
int someVar = 2;
public:
int getSomeVar () {return this->someVar;}
};
int main()
{
Base B = Base();
Derived D = Derived();
Base *PointerToDerived = &D;
Base *PointerToBase = &B;
std::cout << dynamic_cast<Derived*>(PointerToDerived)->getSomeVar() << "\n"; //this will work
std::cout << dynamic_cast<Derived*>(PointerToBase)->getSomeVar() << "\n"; //this will create a runtime error
return 0;
}
有没有更好的方法来设计它,所以不需要强制转换,可以避免像这样的运行时错误?
答案 0 :(得分:2)
是的,你可以在没有任何演员的情况下做到这一点:
class Base
{
public:
virtual ~Base() {}
virtual int getSomeVar () = 0;
};
class Derived : public Base
{
protected:
int someVar = 2;
public:
virtual int getSomeVar () {return this->someVar;}
};
int main()
{
// Base B = Base(); // will not compile, therefore you're safe
Derived D = Derived();
Base *PointerToDerived = &D;
// Base *PointerToBase = &B;
std::cout << PointerToDerived->getSomeVar() << "\n"; // no cast needed
return 0;
}
如果您还希望能够构建Base
课程,您只需提供一个&#34;默认&#34;该方法的实现,而不是纯虚拟。
(另外,在这种特殊情况下,方法应为const
)
答案 1 :(得分:1)
如果我理解正确,你想在基类上调用派生类的函数。这个定义不明确。
相反,您可以在基类中声明一个虚拟函数,该函数将被派生类覆盖。有关详细信息,请参阅Why do we need Virtual Functions in C++?和Wikipedia: Virtual Function。
答案 2 :(得分:0)
这里有一个很好的“功能性”可重用技巧:
template<typename Interface, typename Class, typename Function>
void with(Class * anObject, Function f) {
if (auto * i = dynamic_cast<Interface*>(anObject))
f(*i);
}
用法:
with<Derived>(PointerToBase, [](auto &derived) {
std::cout << derived.getSomeVar() << "\n"; // wont be called
}
with<Derived>(PointerToDerived, [](auto &derived) {
std::cout << derived.getSomeVar() << "\n"; // will be called
}
的示例
答案 3 :(得分:0)
避免运行时错误。
Derived* derived = dynamic_cast<Derived*>(PointerToBase);
if (derived != NULL) {
std::cout << ->getSomeVar() << "\n";
}
当然,您无法将Base
投射到Derived
。
答案 4 :(得分:0)
visitor pattern使用double dispatch允许您使用特定于类的成员函数和成员变量(与通过层次结构可用的成员函数/变量相对)。
要实现访问者模式,您需要访问者和访问的层次结构(在您的示例中它是Base
以及派生的类来自Base
)。
用你的例子,它会给出类似的东西:
class Base
{
public:
virtual ~Base() {}
virtual void visit(Visitor) = 0;
};
class Derived : public Base
{
protected:
int someVar = 2;
public:
int getSomeVar () {return this->someVar;}
void visit(Visitor& v) {
v.visit(this);
}
};
class Visitor {
public:
void visit(Derived& d) {
bar(d.someVar);
}
};
访问者背后的想法是this
的{{1}}知道它的真实类型,而多态变量(Derived
或Base&
)不是&#39 ;吨。覆盖Base*
,您可以致电Base::visit
,他们将向右visit
发送电子邮件。
如果您没有覆盖Visitor::visit
,则在Base::visit
(或Base&
)上调用它时,它会在Base*
对象上调用该函数(所以Base
的类型为this
)。这就是为什么示例Base*
是抽象的,否则只会使错误更容易发生(比如忘记覆盖Base::visit
)。
在visit
层次结构中添加新类型(例如Base
类)时,您需要添加两个函数:Derived2
和Derived2::visit
(或{ {1}})。
修改强>