基础课程
class Base
{
public:
Base()=default;
virtual void f(){cout << "base class\n";}
virtual ~Base(){}
};
派生类
class Derive : public Base
{
public:
Derive()=default;
void f() override {cout << "derived class\n";}
};
主要功能
int main()
{
Base* bsd = new Base;
Derive* dru = new Derive;
if(Derive* drd=dynamic_cast<Derive*>(bsd)){
drd->f();
cout << "downcast successful\n";
}else{
cout << "downcast failed\n";
}
if(Base* bsu=dynamic_cast<Base*>(dru)){
bsu->f();
cout << "upcast successful\n";
}else{
cout << "upcast failed\n";
}
delete bsd;
delete dru;
}
事实证明,upcast工作正常,而downcast失败了。这种方式似乎有道理。如果派生类包含未在基类中声明但没有默认构造函数的成员对象,那么在向下转换期间会发生什么?
此外,通过*drd(*bsd)
创建的目标指针dynamic_cast
指向要投射指针*bsu(*dru)
的同一对象。所以删除一次就足够了。我们不会有一个悬垂的指针,对吧?
答案 0 :(得分:0)
Casting不会以任何方式创建任何新内容或更改对象。转换会更改现有对象的解释,因此如果对象不是Derive
,则无法通过转换使其成为Derive
。
请注意,Derive
也是Base
,因为继承会创建“是一种”关系。这就是为什么向上转换有效:它所做的就是告诉编译器它应该将指向对象视为Base
,即使该对象实际上是Derive
。
它对你的程序没有任何影响,所以这里是一个演员阵容的例子:
class Derive : public Base
{
public:
Derive()=default;
void f() override {cout << "derived class\n";}
void added() {cout << "hello" << endl; }
};
dru->added(); // Works
Base* bsu=dynamic_cast<Base*>(dru);
bsu->added(); // Does not compile
基本上,强制转换“隐藏”了编译器添加的接口,命令它将Derive
对象视为Base
。当然,继续正确调用覆盖,因为覆盖成员函数是Base
接口的一部分。
答案 1 :(得分:0)
我不确定我的问题是否正确,但是,如果析构函数是virtual
,您可以使用基指针安全地删除派生类。
“悬空指针”是不同的:删除bsd
和dru
后,你不能再使用这些指针,它们已成为悬空指针,因为它们指向已删除的内存不再拥有了。
答案 2 :(得分:0)
dynamic_cast检查运行时类型检查并提供安全转换。如果可以进行有意义的转换,那么您可以在向下转换后获得有效的对象。正如您所指出的,在您的示例中,底层对象是&#34;基类&#34;。运行时类型检查失败。但是,如果基础对象是&#34; derieved class&#34; dynamic_cast会成功的。例如:
class CBase
{
public:
CBase(void);
virtual ~CBase(void);
virtual void identify()
{
std::cout << "base class" << std::endl;
}
};
class CDerieved : public CBase
{
public:
CDerieved(void);
virtual ~CDerieved(void);
virtual void identify()
{
std::cout << "Derieved class" << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
CDerieved* pderieved = new CDerieved;
pderieved->identify();
CBase* pb = static_cast<CBase*>(pderieved);
pb->identify();
CDerieved* pd1 = dynamic_cast<CDerieved*>(pb);
pd1->identify();
return 0;
}
上述代码将成功。
但请记住,如果你发现需要垂头丧气,那么设计需要修改。