是否可以通过向下转换从基础对象创建派生对象?

时间:2015-10-31 19:42:24

标签: c++ dynamic-cast

基础课程

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)的同一对象。所以删除一次就足够了。我们不会有一个悬垂的指针,对吧?

3 个答案:

答案 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,您可以使用基指针安全地删除派生类。

“悬空指针”是不同的:删除bsddru后,你不能再使用这些指针,它们已成为悬空指针,因为它们指向已删除的内存不再拥有了。

答案 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;
}

上述代码将成功。

但请记住,如果你发现需要垂头丧气,那么设计需要修改。