menu

hjk41的日志

Avatar

Effective C++ 39: Avoid casts down the inheritence hierarchy

Casting down the inheritence hierarchy, also known as downcasting, means casting a pointer or reference of a base class to those of a derived class.
Suppose we have base class B and derived class D declared like this:


class B{
    ...
}
class D{
public:
    void mf();
    ...
}

B* allObjs[10];
void allMF(){
    B * p;
    for(int i=0;i<10;i++){
        p=allObjs[i];
        p->mf();        // error! class B don't have member function mf()
    }
}


This code won't compile because mf() is not a member function of class B. In this case, one may try this:

void allMF(){
    B * p;
    for(int i=0;i<10;i++){
        p=allObjs[i];
        static_cast<D*>(p) ->mf();        // OK, it compiles now
    }
}


However, there is danger here. If allObjs contains objects that is not of class D, then the static_cast would be a disaster. Even if we have only objects of class D now, what if some other kinds appear in the future?
So the wise thing to do is avoid downcasting, or at least avoid downcasting using static_cast.
Declare a pure virtual function mf() in class B and everything would be fine.
Another way out is using dynamic_cast instead of static_cast. When you use dynamic_cast on a pointer, the cast is attempted, and if it succeeds (i.e., if the dynamic type of the pointer is consistent with the type to which it's being cast), a valid pointer of the new type is returned. If the dynamic_cast fails, the null pointer is returned.
If we have one more derived class D2, then the code would be:

class B{
    ...
}
class D{
public:
    void mf();
    ...
}
class D2{
public:
    void mf();
    ...
}

B* allObjs[10];
void allMF(){
    B * p;
    for(int i=0;i<10;i++){
        p=allObjs[i];
        if(D* p=dynamic_cast<D*>(p))
            p->mf();
        else if(D2* p=dynamic_cast<D2*>(p))
            p->mf();
        else
            cout<<"unknown type"<<endl;
    }
}


With this code, if we add a new class D3 without changing the code in allMF(), we will get an error of "unknown type".
However, using dynamic_cast is vastly inferior to using virtual functions. It must be used only when we are not able to change the code of the classes (e.g. when they are declared in a library).

评论已关闭