OOP with C++ : concept question --- violate access control by polymorphism

Hi all:

I find myself a bit confused by the following question. I don't find anything explaining this topic:

Question:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Base
{
public:
  virtual void print ()
  {
     cout << "Base::print" << endl;
  }
};

class Derived : public Base
{
protected: // attention HERE: different access control
  void print ()
  {
     cout << "Derived::print" << endl;
  }
};



All the books discuss late binding with the same access control. In my example above, if you the following in main(), like:
1
2
        Base * derived = new Derived();
	derived->print();


You will see the output being : Derived::print


That implies, indeed like many books keep telling us: if the function in Base class is virtual and we have a function with the same signature (name + parameter list), then "override" takes place.

But think about the case, it doesn't make sense:
we are able to call the print() function in Derived class! Notice that the print() function is protected. We've violated the access control, by means of polymorphism.


Who can explain this to me, please?

I don't seem to have found a satisfactory answer so far.
you can call it even if its private. Calling a function using a base pointer makes it public even if that's declared private.

If you call it using derived pointer, indeed it will protected.
@writetonsharma:

Many thanks for replying so quickly!

I agree with you. But what we are seeing is the fact. What really confuses me is, I don't see the reason to observe this fact, although "Everything in existence is reasonable."


From a programming language design perspective, late binding is for run time determination of method to be used (flexibility) and access control is for access control (I think the wording is self evident). Those two concepts should not be twisted with each other at all.


So why do we observe the "unreasonable" fact?
Access control is determined at compile time. So its public which is seen by the compiler. But at run time the pointer changes. So I think it reasonable that you have designed this thing this way.

Now you see.. if we have a base pointer which has address of some of the most derived class. This cannot be known until run time. How is the compiler going to tell you that its private and you cannot call it? So no compile time error.

And at the run time if its know that is private, what is the runtime going to do then? Is it going to stop the application? This doesn't seem correct to me... so that's why I think the current behavior is fine.
The way I see it: The Base pointer is a contract that ensures print() is public. Since you are accessing a derived object using the Base contract, the contract must be enforced, ultimately granting access to the protected member because, after all, the derived class agreed to fulfill the contract Base represents when it publicly derived from it.
+1 webJose

The only thing that matters is how it is declared in the base class. This is the only thing the compiler looks at. For this same reason, it is not necessary to redeclare print() as virtual in the derived class; it is implicitly virtual since it is virtual in the base class.
+1 webJose

He nailed it on the head.It is all about contracts. The Base class makes a promise to the programmer. The programmer's code should not break because someone tried to 'change the deal' by passing them an derived object.

And this is useful. In code that needs access to the print() function you can pass it the base class reference. But in code that does not require that interface then you can pass that the derived reference.

This ensures that only the code with a Base class reference can do certain tasks that are restricted from code with the derived class reference.
@All:

Thank you all for taking time to reply! Great answers!
I like the "contract" explanation.

However, here I'm just thinking a bit further:
We know that the latest C++ standard supports keyword "override". This means, the compiler knows who in the Derived class are the successors to the virtual functions in the Base class.
Both pieces below, which are declarations in header file, compile successfully:
1
2
3
4
5
6
7
8
9
10
11
12
class Base
{
public:
  virtual void print ();
  
};

class Derived : public Base
{
public:
  void print () override;
};



1
2
3
4
5
6
7
8
9
10
11
12
class Base
{
public:
  virtual void print ();
  
};

class Derived : public Base
{
protected: // attention HERE: different access control
  void print () override;
};




Since the compiler knows which Derived function is the successor to which Base function, I'm just thinking, it makes more sense for the compiler to enforce the access control at compilation.
Reason:
1, it is technically feasible (similar to implementation of keyword "override", isn't it?)
2, the Base class serves as a contract, and access control is certainly a part of contract.


What do you guys think? Please point out any mistakes or unreasonable inference of mine.
Thanks!

Last edited on
I think it is something for the C++ standard, not us. If the standard decides to go that route, then there you go; if not, then there you go too. :D
@webJose:
Fair enough :D
Thanks for the explanation! Excellent answer.
I think that having a narrower access specifier in the _derived_ class should be treated as a compile time error. And in fact all the truly OOP languages I know (C#, Scala, Java) enforce this - you just cannot override a public method with a protected or private one. What for? You are deliberately violating the Liskov's substitution principle, so the compiler should tell you that.
Last edited on
@rapidcoder:
+1
In fact, I think this is a bug of C++ design.
:O
Topic archived. No new replies allowed.