Access to private member functions of derived class using reference to a base class

202 views Asked by At

Take a look at the code. I have interface which looks like this:

class Abstract_base {
    public:
        virtual ~Abstract_base() {}

        virtual void f1 () = 0;
        virtual void f2 () = 0;
};

Base class looks like this:

class Base : public Abstract_base {
    public:
        virtual ~Base() {}

        virtual void f1 () override { cout << "f1" << endl; }
        virtual void f2 () override { cout << "f2" << endl; }
};

and I have two derived class, like this:

class Derived_1 : public Base {
    public:
        virtual ~Derived_1() {}

    private:
        virtual void f2 () override { cout << "Derived_1::f2 ()" << endl; }

};

class Derived_2 : public Base {
    public:
        virtual ~Derived_2() {}

    private:
        virtual void f1 () override { cout << "Derived_2::f1 ()" << endl; }
};

and finally I have Handler class which looks like this:

class Handler {
    public:
        Handler (Abstract_base& b) : base (b) {}
        virtual ~Handler() {}

        void process_1 () { 
            base.f1 ();
        }

        void process_2 () { 
            base.f2 ();
        }

    private:
        Abstract_base& base;
};

And main.cpp looks like this:

int main (int argc, char** argv) {

    Derived_1 der1;
    der1.f2 ();

    Derived_2 der2;
    der2.f1 ();

    Handler handler1 (der1);
    handler1.process_2 ();

    Handler handler2 (der2);
    handler2.process_1 ();

    return 0;
}

Of course code will not compile because der1.f2 () and der2.f1 () are private, but if I comment out these two instructions and leave the handler1.process_2 () and handler2.process_1 () instructions, code will compile and produce output:

Derived_1::f2 ()
Derived_2::f1 ()

Question:

How can I prevent from calling these two private member functions using reference to the Abstract_base class? I just don't want the user have access to the f2 () in Derived_1 and f1() in Derived_2.

As far as I know I could not use delete keyword for Derived_1::f2 () and Derived_2::f1 ().

Could you suggest me a solution for this problem?

Solution

I know that one of the solution could be make Handler a template class like this:

template <class B>
class Handler_templ {
    public:
        Handler_templ (B& b) : base (b) { }
        virtual ~Handler_templ() {}

        void process_1 () { 
            base.f1 ();
        }

        void process_2 () { 
            base.f2 ();
        }

    private:
        B& base;
};

and use it like this:

Handler_templ<Derived_1> h1 (der1);
Handler_templ<Derived_2> h2 (der2);

h1.process_2 ();
h2.process_1 ();

What surprising me is why using Handler class I am able to invoke these private member function? For any suggestions I would be very grateful.

Sincerely, Artur

3

There are 3 answers

0
πάντα ῥεῖ On

_"How can I prevent from calling these two private member functions using reference to the Abstract_base class? I just don't want the user have access to the f2() in Derived_1 and f1() in `Derived_2"._

There's no way to hide these functions by using the scope operators through a derived class declaration.

"What surprising me is why using Handler class I am able to invoke these private member function?"

As for your samples

class Base : public Abstract_base {
public:
    virtual ~Base() {}
    virtual void f1 () override { cout << "f1" << endl; }
    virtual void f2 () override { cout << "f2" << endl; }
};

class Derived_1 : public Base {
public:
    virtual ~Derived_1() {}
private:
    virtual void f2 () override { cout << "Derived_1::f2 ()" << endl; }
};

class Derived_2 : public Base {
public:
    virtual ~Derived_2() {}
private:
    virtual void f1 () override { cout << "Derived_2::f1 ()" << endl; }
};

it's perfectly OK to override a public base class function, using a private function in the derived class.
These function overrides will still be visible via the Base/Abstract_base class interfaces.

The private scope specifier makes them just inaccessible for directly calling clients.

2
leslie.yao On

You can't prevent from calling these two private member functions using reference to the Abstract_base class. When you access the methods by reference or pointer of the base class, the access rights of derived class will not be considered. (How can the compiler know that?)

According to Liskov Substitution Principle (LSP) ,

Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

0
Ajay On

You cannot do that. You cannot prevent two things:

Derived_1 der1;
((Abstract_base*)&der1)->f2 ();  // 1

And the pointer or reference conversion:

Derived_1 d;

Abstract_base* bp = &d; // 2
Abstract_base& ref = d; // 2

C++ doesn't have provision to stop conversion to base pointer/reference, or to perform object-slicing to base. Neither C++ mandates that derived class must implement virtual function in specified protection level.