[英]In C++ how could I cast a sub class instance from one base class pointer to another without dynamic_cast?
[英]C++ How to access derived class member from base class pointer without using a static_cast or dynamic_cast?
我看到了以下问题 ,我问自己是否有更好的方法来解决此问题,因此不需要强制转换。 考虑以下代码:
#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;
}
有没有更好的方法来设计它,因此不需要强制转换并且可以避免类似的运行时错误?
是的,您无需任何强制转换即可做到:
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
类,则可以提供该方法的“默认”实现,而不是将其纯虚拟化。
(同样,在这种情况下,方法应该是const
)
如果我对您的理解正确,则希望在基类上调用派生类的函数。 这没有很好的定义。
相反,您可以在基类中声明一个虚函数,该虚函数将被派生类覆盖。 请参阅为什么我们需要C ++中的虚函数? 和Wikipedia:虚拟功能了解更多详细信息。
您可以在此处应用一个不错的“功能性”可重用技巧:
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
}
避免运行时错误。
Derived* derived = dynamic_cast<Derived*>(PointerToBase);
if (derived != NULL) {
std::cout << ->getSomeVar() << "\n";
}
当然,您不能将Base
Derived
为Derived
。
访问者模式使用双调度,以允许您使用特定于类的成员函数和成员变量(与成员函数/可通过层次结构使用的变量相对)。
为了实现访问者模式,你需要一个访问者和访问层级(在你的例子是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
的Derived
知道它是真实的类型,而一个多态变量(一个Base&
或Base*
)没有。 压倒一切的Base::visit
让你调用visit
谁做调度向右Visitor::visit
。
如果不重写Base::visit
,在调用它时Base&
(或Base*
),它会调用该函数Base
的对象(所以this
将是类型的Base*
)。 这就是为什么示例Base::visit
是抽象的,否则这样做只会使错误更有可能发生(例如忘记覆盖visit
)。
在Base
层次结构中添加新类型时(例如Derived2
类),您将需要添加两个函数: Derived2::visit
和Visitor::visit(Derived2)
(或Visitor::visit(Derived2&)
)。
编辑
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.