polymorphism bypasses private protection?

Something in C++ that is puzzling me...

Let's say I live in a very quiet apartment with a very mean landlord. If I try to call makeNoise from dogObj with the statement: dogObj->makeNoise(); the compiler informs me I cannot access the private member. That's what I wanted since I only want Fido to bark in emergencies.

But isn't it a bit of a contradiction that I can then call that exact same function from an Animal pointer at runtime? I know polymorphism is not resolved until run-time, so I would not expect a compiler error. But isn't the polymorphic call violating or getting around the "privacy" of Dog::makeNoise() at runtime?

It seems polymorphism offers a way to get around encapsulation?




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>

using namespace std;

class Animal {
	string name;
public:
	virtual void makeNoise() = 0;
};
class Goldfish : public Animal {
public:
	void makeNoise() {
		cout << "Splish Splash \n";} //OK, landlord can't hear splash
};
class Dog : public Animal {
private:
	void makeNoise() {
		cout << "Bark! Bark!\n";}  //Too loud, use only if danger
public:
	void senseDanger() {
		makeNoise(); }
};
void main()
{
	Goldfish* fishObj = new Goldfish;
	fishObj->makeNoise(); //it's OK, landlord cannot hear splashing
	Dog* dogObj = new Dog;
	cout<< "danger sensed, OK to bark \n";
	dogObj->senseDanger();
	//dogObj->makeNoise();//'Dog::makeNoise' : cannot access private member declared in class 'Dog'
	Animal* animalPtr = dogObj;
	cout << "No danger, not OK to bark \n";
	animalPtr->makeNoise(); //dog is barking, landlord kicks me out
}
I know polymorphism is not resolved until run-time, so I would not expect a compiler error. But isn't the polymorphic call violating or getting around the "privacy" of Dog::makeNoise() at runtime?


The first sentence here sums it up. Polymorphism is determined at runtime -- whereas public/private/protected are nonexistent during runtime (it's just something to make compiling nicer). So the privacy of Dog::makeNoise doesn't exist when you run the program, it only matters when you try to compile it.

Your example demonstrates a poor use of public/private qualifiers. Or at least it tries to get them to do something they're not designed to do.

So yes -- you can break encapsulation this way, but only if the encapsulation was poorly designed. Members that are public in the parent class should be public in child classes. To "solve" this, you could change the design slightly:

1
2
3
4
5
6
7
8
9
10
11
12
class Dog : public Animal
{
private:
  void reallyMakeNoise()
  {
    cout << "Bark!\n";
  }

public:
  void senseDanger()  { reallymakeNoise(); }
  void makeNoise()   { /* do nothing */ }
};
Since you are using a pointer to Animal ( which is allowed to make noise ) and that pointer doesn't know to be a Dog ( which is not allowed ). So it makes noise
Or just make the makeNoise() method protected in the base class.
You can still make it public in Goldfish (and because it's a virtual, that's not a totally evil thing to do, but it isn't exactly a good thing to do either).
Your Dog wrapper will work as intended, and there will be no way to call makeNoise() directly from Animal or Dog, or any class where it doesn't get declared public.
**Taken from the C++ standards document**

11.6 Access to virtual functions
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class B {
public:
virtual int f();
};
class D : public B {
private:
int f();
};
void f()
{
D d;
B* pb = &d;
D* pd = &d;
pb->f(); //OK: B::f() is public,
// D::f() is invoked
pd->f(); //error: D::f() is private
}

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.
Thanks very much Disch, Bazzy, jRaskell, and guestGulkan... for all of your comments. I am all ears, I am learning so much from this forum! Thanks again.
Topic archived. No new replies allowed.