Virtual function breaking private access

2019-07-17 19:52发布

问题:

I recently came across this article on IBM site. Below is the sample code

#include "iostream"

class B {
public:
  virtual void f()
  {
    std::cout<<"\n In class B";
  }
};

class D : public B {
private:
    int i;

  void f()
  {
  std::cout<<"\n In class D i = "<<i;
  }
  public:
    D(int i_num):i(i_num)
    {}
};

int main() {
  D dobj(10);
  B* bptr = &dobj;
  D* dptr = &dobj;

  // valid, virtual B::f() is public,
  // D::f() is called
  bptr->f();

  // error, D::f() is private
  //dptr->f();
}

We are now able to call private function of D.I wanted to know doesn't this break C++ encapsulation ?

P.S. : Please go to Virtual function access section in Virtual function. I do not know why I am not getting exact link when I do paste.

回答1:

Access-specifiers are compile-time construct, and so, the compiler detects any violation of access-rules at compile-time (obviously) based on the static type of the object (or pointer). Such violation cannot be detected at runtime.

So bptr->f() works, because the compiler sees that the static type of bptr is B which has a public function f() defined, so the expression bptr->f() passes the compiler's test. Hence it works.

But dptr->f() doesn't work, since the static type of dptr is D which has a private function f(), hence the code wouldn't even compile!

Now whether it breaks encapsulation or not, is a very subjective question and will receive subjective answers. It entirely depends on how one defines it and the arguments directly flows from it. There is no one universal definition. My personal opinion is, if the language allows it, then (it would imply that) according to the C++ community, it doesn't break encapsulation, or if it does, then C++ allows it so as to achieve something very nobel (which otherwise isn't possible). Otherwise, I would say its just yet another misfeature of C++ just like the following:

Default argument in the middle of parameter list?



回答2:

The call bptr->f() is evaluated at run time depending on the type of objected pointed by bptr. At compile time the compile sees the bptr->f() call as call to B::f() and since B::f() is public the compiler doesn't report only error. It is only at runtime that actual function call D::f() is evaluated.

This doesn't break the Encapsulation principle this is a feature of C++ called Run-time Polymorphism or Dynamic Polymorphism

You cannot directly call dptr->f() because D::f() is declared under Private Access specifier and You cannot access privately declared members from outside the class.



回答3:

It is by design.

B::f is public. User access of f via a pointer to B is allowed. Since f is virtual, the call would be dispatched to derived classes' f.

But D::f is private, you can't access f via a pointer do D.



标签: c++ virtual