Rachit Jain
Rachit Jain

Reputation: 41

Calling private functions in C++ from base class pointers

Lets have a class B deriving from class A.
B has a private member void secret() while A has public virtual void secret()

B obj;
A* ptr = &obj;
ptr->secret(); //calls the private function secret in class B.

Now, the following code works successfully. Isn't this bad? Shouldn't the vtable also take care of whether the underlying function is accessible or not?

Here is the source code with more detail and good example.
Here is my youtube video talking about the same.

Upvotes: 4

Views: 3596

Answers (4)

Geezer
Geezer

Reputation: 5730

First of all it is legal – as the vtable does not take part in denoting the access during a call – as the C++ Standard [class.access.virt] says:

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 (B* in the example above). The access of the member function in the class in which it was defined (D in the example above) is in general not known.

That said, the SOLID principles are considered to be pillars of good code design. The 'L' in SOLID stands for the Liskov Substitution Principle, according to which:

if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e. an object of type T may be substituted with any object of a subtype S) without altering any of the desirable properties of the program.

So you see, by changing access of, let's say a public member in the base class, we would undoubtedly alter the interface of this derived object of type S, when trying to use it as a T. Thus constraining usage of it by other parts of the program, thus changing its properties and so breaking the Liskov Principle.

Furthermore, a comprehensive authority for such matters of usage and design would be the C++ FAQ, According to which this hiding of derived members (virtual or not) usually indicates bad practice:

Should I hide member functions that were public in my base class?
Never, never, never do this. Never. Never!

For the avid reader: The C++ FAQ says the following about virtual methods:

there really are two different basic ways to use virtual functions:

Suppose you [...] you have a method whose overall structure is the same for each derived class, but has little pieces that are different in each derived class. So the algorithm is the same, but the primitives are different. In this case you’d write the overall algorithm in the base class as a public method (that’s sometimes non-virtual), and you’d write the little pieces in the derived classes. The little pieces would be declared in the base class (they’re often protected, they’re often pure virtual, and they’re certainly virtual), and they’d ultimately be defined in each derived class. The most critical question in this situation is whether or not the public method containing the overall algorithm should be virtual. The answer is to make it virtual if you think that some derived class might need to override it.

Suppose you have the exact opposite situation [...], where you have a method whose overall structure is different in each derived class, yet it has little pieces that are the same in most (if not all) derived classes. In this case you’d put the overall algorithm in a public virtual that’s ultimately defined in the derived classes, and the little pieces of common code can be written once (to avoid code duplication) and stashed somewhere (anywhere!). A common place to stash the little pieces is in the protected part of the base class, but that’s not necessary and it might not even be best. Just find a place to stash them and you’ll be fine. Note that if you do stash them in the base class, you should normally make them protected, since normally they do things that public users don’t need/want to do. Assuming they’re protected, they probably shouldn’t be virtual: if the derived class doesn’t like the behavior in one of them, it doesn’t have to call that method.

So no changing of virtual member access in derived class is not mentioned here in either use-case of virtualization. As such, I'd also take it there is no known good usage for such tactic.

Upvotes: 2

Christophe
Christophe

Reputation: 73587

As already explained very well by others, this works exactly as by the C++ rules. The key design assumption of the C++ language is that the programmer knows what he's doing:

C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off.
- Bjarne Stroustrup

Here, your design is flawed ! You want B to inherit from A (so B is an A), but at the same time, you want that it can't be used like an A (so B is not really an A after all):

class A {
public: 
    virtual void greet() { cout <<"Hello, I'm "<<this<<endl;}
    virtual void tell() { cout<<"I talk !"<<endl; }
};
class B : public A {
private:
    void greet() override { cout <<"Hello, I can tell you privatly that I'm "<<this<<" incognito"<<endl;}
};

Humans can be confused by such paradoxical injunction. The C++ compiler thinks you must have good reasons to do so and plays by the book:

A a; 
a.greet();        // ok 
B b; 
b.greet();        // error:  you said it was not accessible  
A& b_as_a = b; 
b_as_a.greet();   // ok:  you said that A's interface had to be used

If you want A's public functions to be inaccessible, you should tell the compiler by using non public inheritance:

class C : protected A {
private:
    void greet() override { cout <<"Hello, I can't tell you anything, but I'm "<<this<<endl;}
};

This means that a C is implemented based on an A, but that the outside world shouldn't knwow it. This is much cleaner:

C c;  
c.greet();             // error, as for B 
A& c_as_a = c;         // ouch: no workaround: because the A inheritance is procteted 

Typically, you'd use this kind of inheritance if you want to reuse A's features to build a C class with a completely different interface. Yes, C++ can enforce tighter rules if you ask :-).

Typically, you would exposed completely different functions. But what if you'd want to use one of A's public function for convenience, it's easy:

class C : protected A {
private:
    void greet() override { cout <<"Hello, I can't tell you anything, but I'm "<<this<<endl;}
public: 
    using A::tell;     // reuse and expose as it is
};

Upvotes: 0

Sanjeev
Sanjeev

Reputation: 358

No this is not bad, as you are calling the method from the base class object pointer and in base class the method is declared as public. If you try B* ptr = &obj and try accessing method from ptr pointer then it will not be allowed.

So the type of pointer will decide the method specifier always.

Upvotes: 1

TheOperator
TheOperator

Reputation: 6516

In C++, a member function's visibility and it being virtual/non-virtual are widely orthogonal to each other. Other languages following a more strict OOP approach (such as Java) are not as flexible in this regard.

From a design perspective, hiding a public overridden usually doesn't make sense. However, consider that there is private inheritance in C++, which would make the base class A an implementation detail of B, and as such you wouldn't expose members of the base class.

Upvotes: 1

Related Questions