我对多态性有疑问
using namespace std;
class Base {
public:
Base(int v) { u = v; };
virtual ~Base(){};
int u;
void f() { /* operations on u */ };
};
template<class T>
class Derived: public Base {
public:
T t;
Derived() { }
void g() { std::cout << u; /* operations on t and u */ }
};
int main() {
Base *b = new Base(1);
b->f();
if (b->u == 1) {
Derived<int> *d = dynamic_cast<Derived<int> *>(b);
d->g();
}
return 0;
}
使用d-> g()会有段错误。是否可以在演员后在Derived对象中访问u?该程序的目的是构造一个具有未知类型的类(关于此的信息只能在构造类对象之后才可用,例如读取jpg文件的类,深度信息事先不知道)。或者是否存在针对此类问题的设计模式?谢谢你的任何提示。
答案 0 :(得分:2)
您的代码段错误不是因为Base::u
中没有*b
,而是因为d
是nullptr
并且取消引用它会调用未定义的行为。根据规范,dynamic_cast<T*>(p)
为您提供
T
的{{1}}对象的指针(如果有)或*p
。由于nullptr
未指向b
类型的对象,因此您获得了Derived<int>
。稍后,当您尝试使用nullptr
时,您的程序会出现段错误。
请注意,如果nullptr
为引用,则行为会有所不同。 dynamic_cast
将
dynamic_cast<T&>(r)
所属T
对象的引用(其中r
为参考)或r
如果没有此类对象,则为throw
类型的例外。因此,您通常会通过以下任一方式使用std::bad_cast
。
如果您想测试对象的动态类型,并在某个dynamic_cast
时对其进行处理:
class
如果您(认为您)确定指针指向(动态)类型if (auto d = dynamic_cast<D*>(b))
{
// We have a D object here (d != nullptr), use it.
d->use();
}
else
{
// We don't have a D object (d == nullptr) here.
}
的对象:
D
在您的情况下,似乎您有dynamic_cast<D&>(*b).use();
某种约定应该暗示动态类型b->u == 1
为*b
的约定,因此您可能会考虑Derived<int>
参考。 (如果没有别的,它会在这里给你一个比“分段错误”更有用的错误信息。)当然,现在你知道dynamic_cast
的行为,你可能会摆脱那个“约定”并测试动态直接通过dynamic_cast
键入指针。无论如何,您首先必须解决Sam Varshavchik的answer中描述的问题。
有关dynamic_cast
的详细信息,请查看cppreference.com。
答案 1 :(得分:1)
不,这是不可能的。
这是因为您构建了Base
的实例,而不是Derived
的实例。你可能打算这样做:
Base *b = new Derived<int>();
但这也不会起作用,因为Base
没有默认的构造函数。
您将永远无法使用此代码实例化任何Derived<T>
,因为Derived
尝试使用Base
的默认构造函数,但它没有之一。
dynamic_cast<T>
并非用于创建类的新实例,并附加到现有类中,凭空捏造。它用于解析超级或子类的现有实例,它与动态转换的实例所属的类相关。