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

Is it possible to creat a derived object from a base object through downcast?

基地class

class Base
{
public:
    Base()=default;
    virtual void f(){cout << "base class\n";}
    virtual ~Base(){}
};

派生class

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 失败了。这么说好像也有道理。如果派生 class 包含未在基 class 中声明的成员对象并且没有默认构造函数,那么在向下转型期间会发生什么?

此外,通过dynamic_cast创建的目标指针*drd(*bsd)与要转换的指针*bsu(*dru)指向同一个对象。所以删除一次就足够了。我们不会有悬空指针吧?

转换不会以任何方式创建任何新对象或更改对象。转换会更改现有对象的解释,因此如果对象不是 Derive,则无法通过转换使其成为 Derive

请注意 Derive 也是 Base,因为继承会创建 "is a" 关系。这就是向上转型起作用的原因:它所做的只是告诉编译器它应该将指向的对象视为 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

本质上,强制转换 "hides" 从编译器添加了接口,命令它像 Base 一样对待 Derive 对象。当然,覆盖继续被正确调用,因为覆盖的成员函数是 Base 接口的一部分。

我不确定我是否答对了你的问题,但是是的,如果析构函数是 virtual.

,你可以使用基指针安全地删除派生的 class

一个"dangling pointer"是不一样的:当你删除了bsddru之后,你就不能再使用这些指针了,它们变成了悬挂指针,因为它们指向的是被删除的指针你不再拥有的记忆。

dynamic_cast 检查 运行 时间类型检查并提供安全转换。如果有意义的转换是可能的,那么在沮丧之后你会得到一个有效的对象。正如您所指出的,在您的示例中,基础对象是 "base class"。 运行 时间类型检查失败。但是,如果基础对象是 "derieved class" 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;
}

上面的代码会成功。

但请记住,如果您发现需要降压,则设计需要修改。