c++inheritancemember-hiding

Hide, overload or overwrite in C++


Then I have a question again. something like this:

#include <iostream>
using namespace std;

class Base
{
public:
    void foo()
    {
        cout<<"Base."<<endl;
    }
};

class Derive:public Base
{
public:
    void foo()
    {
        cout<<"Derive."<<endl;
    }
};

int main()
{
    Derive d;
    Base *pb=&d;    //attention here
    pb->foo();      //ateention here
    system("pause");
    return 0;
}

And the output is "Base.". Then the function rules are't work, I am confused about this, could you help me? Thanks.


Solution

  • Since foo is not virtual, the function called is based on the static type (i.e., the type the pointer is declared to point at) rather than the dynamic type (the type of object to which the pointer currently refers).

    There are also some trickier cases to consider. One point (on which some of the other answers are actually somewhat misleading) is that it's not really just the function name that matters, but the entire function signature. For example:

    #include <iostream>
    
    struct base { 
        virtual void foo() { 
            std::cout << "base::foo";
        }
    };
    
    struct derived : base { 
        virtual void foo() const { 
            std::cout << "derived::foo";
        }
    };
    
    int main(){ 
        base *b = new derived;
    
        b->foo();
    }
    

    Here foo is qualified as virtual in both the base and (seemingly redundantly the) derived classes, but the call b->foo() still prints out base::foo.

    The const added to the signature of derived::foo means it no longer matches the signature of base::foo, so instead of overriding the virtual function, we still end up with two separate functions with the same name, so derived::foo hides base::foo, but doesn't override it. Despite the virtual qualification, we get static binding, so b->foo(); invokes the base function rather than the derived, even though b points to an object of the derived type.

    As Tony D pointed out in a comment, C++11 added a new wrinkle to the language to help ensure against this happening. When you want to override a base class function, you can add the identifier override to the function in the derived class:

    struct derived : base {
         virtual void foo() const override {
             std::cout << "derived::foo";
         }
    };
    

    With this, if there's a difference in function signature (as in the cases shown here), the compiler will produce an error message alerting you to the fact that derived::foo is marked as override, but doesn't actually override a function from the base class. This was, however, added in C++11, so if you're using an older compiler this feature may not be implemented (though thankfully, compilers that don't implement it are quickly fading into oblivion).

    Correcting the signature in the base class to:

    virtual void foo() const // ...
    

    ...will let the code compile, and produce the correct results.