If a private virtual function is overridden as a p

2019-01-19 08:08发布

问题:

using namespace std;
#include <cstdio>
#include <iostream>

class One{
    private:
        virtual void func(){
            cout<<"bark!"<<endl;
        }
};

class Two: public One{
    public:
        void func(){
            cout<<"two!"<<endl;
        }
};

int main(){
    One *o = new Two();
    o->func();
}

Why is there an error on o->func()?

I don't know the mechanism behind it... In my opinion, o->func() should call the func() in the derived class, which is public, so there wouldn't be problems, but it says:

 error: ‘virtual void One::func()’ is private

回答1:

Accessibility check is performed based on the static type of the object. The type of o is One*. This means that if One::func() is private, then o->func() won't compile.

On the other hand, which virtual member function will be called (i.e. dynamic dispatch) happens at run-time, based on the dynamic type of the object. So if One::func() is public, o->func() will call Two::func(), because o is pointing to an object of type Two.

For your sample code and use case, making One::func() private is just meaningless. But note that there's a famous idiom called Non-Virtual Interface, which makes use of private virtual member functions of base class.


Other suggestions:

  1. Don't forget to delete o;
  2. Add a virtual destructor in the base class One. Otherwise delete o; will lead to undefined behavior; e.g. the destructor of Two might not be invoked.

    class One {
        public:
            virtual ~One() {}
        // ...
    };
    


回答2:

A subclass can't ease inheritance restriction, even though func is virtual, it is still the inheritance restrictions remain.

please see this answer for compliated view of inheritance restrictions :

Difference between private, public, and protected inheritance



回答3:

Please check Access specifiers and virtual functions.

From standard :

§11.5 [class.access.virt] The access rules (Clause 11) for a virtual function are determined by its declaration and are not affected by the rules for a function that later overrides it.

Access is checked at the call point using the type of the expression used to denote the object for which the member function is called. The access of the member function in the class in which it was defined is in general not known.

If name lookup determines a viable function to be a virtual function, the access specifier of the virtual function is checked in the scope of the static type of the object expression used to name the function. At run time, the actual function to be called could be defined in the derived class with a completely different access specifier. This is because 'access specifiers' are a compile time phenomenon.

Since access specifier of function func() is checked in the scope of One *o, and it is private in class One, it produces error.

If Onedeclares func() as public, and Two declares it private, there won't be any errors. See this Private function invoked and it works. Could any of you reason it please