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

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

本文关键字:对象 创建 派生 可以通过 转换 是否      更新时间:2023-10-16

基类

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

派生类

class Derive : public Base
{
public:
    Derive()=default;
    void f() override {cout << "derived classn";}
};

主要功能

int main()
{
    Base* bsd = new Base;
    Derive* dru = new Derive;
    if(Derive* drd=dynamic_cast<Derive*>(bsd)){
        drd->f();
        cout << "downcast successfuln";
    }else{
        cout << "downcast failedn";
    }
    if(Base* bsu=dynamic_cast<Base*>(dru)){
        bsu->f();
        cout << "upcast successfuln";
    }else{
        cout << "upcast failedn";
    }
    delete bsd;
    delete dru;
}

事实证明,上行传输效果良好,而下行传输失败。这样看来是有道理的。如果派生类包含未在基类中声明的成员对象,并且没有默认构造函数,那么在下转换过程中会发生什么?

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

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

请注意,Derive也是Base,因为继承会创建"是"关系。这就是upcasting工作的原因:它所做的只是告诉编译器,它应该将指向的对象视为Base,即使该对象实际上是Derive

它在你的程序中没有什么不同,所以这里有一个演员阵容的例子:

class Derive : public Base
{
public:
    Derive()=default;
    void f() override {cout << "derived classn";}
    void added() {cout << "hello" << endl; }
};
dru->added(); // Works
Base* bsu=dynamic_cast<Base*>(dru);
bsu->added(); // Does not compile

从本质上讲,强制转换对编译器"隐藏"添加的接口,命令它将Derive对象视为Base。当然,重写将继续被正确调用,因为重写成员函数是Base接口的一部分。

我不确定你的问题是否正确,但是的,如果析构函数是virtual,你可以使用基指针安全地删除派生类。

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

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

以上代码将成功。

但请记住,如果你发现需要向下转换,那么设计需要修改。