0
votes

Base class

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

Derived class

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

main function

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

It turns out upcast works fine, while downcast failed. It seems makes sense that way. If the derived class contain member objects that are not declared in the base class and do not have default constructors, what gonna happen during downcast?

Besides, the target pointer *drd(*bsd) created through dynamic_cast points to the same object with the pointer *bsu(*dru) to be cast. So delete once will be enough. We will not have a dangling pointer, right?

3
static cast the drived class instead of dynamicMORTAL

3 Answers

0
votes

Casting does not create anything new or changes objects in any way. Casting changes the interpretation of an existing object, so if an object is not a Derive, there is no way to make it a Derive through casting.

Note that Derive is also a Base, because inheriting creates an "is a" relationship. That's why upcasting works: all it does is telling the compiler that it should treat the pointed to object as Base, even though the object is actually Derive.

It makes no difference in your program, so here is an illustration of what the cast does:

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

Essentially, the cast "hides" added interfaces from the compiler, ordering it to treat a Derive object as if it were Base. Of course, the overrides continue to be called correctly, because the overriden member-functions are part of the Base's interface.

0
votes

I'm not sure I got your question right, but yes, you can safely delete a derived class using a base pointer, if the destructor is virtual.

A "dangling pointer" is something different: After you have deleted bsd and dru, you can not use these pointers anymore, they have become dangling pointers, because they point to deleted memory that you don't own anymore.

0
votes

dynamic_cast checks run-time type check and provides a safe conversion. If a meaningful conversion is possible then you'd get a valid object after downcast. As you pointed out, in your example the underlying object was of "base class". Run time type check failed. However if the underlying object was of "derieved class" dynamic_cast would have succeeded. ex:

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

The above code will succeed.

But please remember, if you find needing a downcast, then the design needs to be revised.