I got surprised that a public(or private) virtual function can be overridden by a private(or public) virtual function. See below,
class C{
public:
virtual void f(){cout<<"C"<<endl;}
void g(){f();}
};
class D:public C{
private:
virtual void f(){cout<<"D"<<endl;}
};
int main(){
C * c = new D;
c->g();
return 0;
}
the code outputs D. I thought virtual function can only be overridden in the derived class with the same access specifier as in the base class, but this is apparently not how the above code works, am I observing something wrong? Why the access specifiers (public, protected and private) don't put restrictions on how the virtual function is overridden?
The C++11 Standard does not mention anything about the access specifiers of virtual functions in 10.3 Virtual Functions, at least I cannot find any.
Given that, D::f() is not directly accessible through an object or pointer of type D.
D* dPtr = new D;
dPtr->f(); // Does not work.
The following works:
C* cPtr = new D;
cPtr->f();
since C::f() is a public member function of C.
Update
Upon further investigation, I found the following:
11.5 Access to virtual functions
1 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. [ Example:
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
}
— end example ]
Related
I has this code:
struct A {
virtual void f() {}
};
struct B: A {
private:
void f() override {}
};
...
B b;
A& a = b;
a.f();
And ofcourse it will call f() from B cause private is checked on the compilation time but choosing virtual function version are in the runtime. Can I forbid f() calling in this case?
No. As you call f() on an A reference, the access rules are checked on A. You can't expect the compiler to check the rules for B, because it does not necessarily know that a is of type B.
From cppreference:
Access rules for the names of virtual functions are checked at the call point using the type of the expression used to denote the object for which the member function is called. The access of the final overrider is ignored:
struct B { virtual int f(); }; // f is public in B
class D : public B { private: int f(); }; // f is private in D
void f() {
D d;
B& b = d;
b.f(); // OK: B::f is public, D::f is invoked even though it's private
d.f(); // error: D::f is private
}
Your code should not rely on this though. In my opinion, access specifiers for a given method should be consistent across the class hierarchy.
When I am trying to delete the derived object polymorphically (that is: base class has public virtual destructor) why derived class private destructor is still being called? Why the scope resolution private is not working here.
class Base
{
protected:
Base() { cout << "Base constructor.\n"; }
public:
virtual ~Base() { cout << "Base destructor.\n"; }
};
class Derived :public Base
{
public:
Derived() { cout << "Derived constructor.\n"; }
private:
~Derived() { cout << "Derived destructor.\n"; }
};
int main()
{
Base *p = new Derived();
delete p;
}
Output:
Base constructor.
Derived constructor.
Derived destructor.
Base destructor.
Because destructors are called in reversed order of constructors and virtual destructor will always be called.
private has nothing to do if a virtual function is going to be called.
As I pointed here out:
Why would a virtual function be private?
ISO C++ 1998 Standard onwards explicitly states:
§10.3 [...] Access control (clause 11) is not considered in determining overriding.
A bit philosophical offtopic:
Going further this is what STL does for iostreams: Definition of Non-Virtual Interface, i.e. all public functions (with exception of destructors) are non-virtual and all virtual functions are either protected or private. Public functions call virtual protected or private ones. This gives a very clear entry point into the entire hierarchy.
It is, but you're not calling ~Derived() directly. If you were to use
Derived *p = new Derived();
delete p;
then you'd get the error. But when you access ~Derived() indirectly via polymorphism (e.g. by calling ~Base()), then the access specifier private does not apply.
According to [class.access.virt#1]:
The access rules (Clause [class.access]) for a virtual function are determined by its declaration and are not affected by the rules for a function that later overrides it. [ Example:
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
}
— end example ]
And again in footnote 111 in [class.virtual]:
Access control is not considered in determining overriding.
You use a virtual destructor because you want all the destructor in your inheritance to get called. That exactly what you get. The private does not apply as you don't call the destructor explicitly.
If your destructor was not virtual you will get only Base::~Base() called. Usually that's not what you want when you have polymorphism.
You can call the destructor through a pointer to B, because it's already public there. It's the static type of the pointer which is used to determine that access in this case.
[class.access.virt/1]
The access rules (Clause [class.access]) for a virtual function are
determined by its declaration and are not affected by the rules for a
function that later overrides it. [ Example:
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
}
— end example ]
This keeps virtual functions in line with the Liskov Substitution Principle
You delete the derived class through the base class pointer. With the help of the virtual destructor you start the delete at the derived class. Because that class can access its private members, it call the private destructor. After that the base class is calling the public destructor.
Note that you call delete and not calling de destructor Derived::~Derived() direct!
In the example below, why is B::f() called even though it is private?
I know this fact that :
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.
#include <iostream>
class A {
public:
virtual void f() { std::cout << "virtual_function"; }
};
class B : public A {
private:
void f() { std::cout << "private_function"; }
};
void C(A &g) { g.f(); }
int main() {
B b;
C(b);
}
Because the standard says so:
[C++11: 11.5/1]: 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. [ Example:
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
}
—end example ]
The example is the same as yours, lol.
private functions can override public virtual functions from a base class. Accessability is, in a fact, completely ignored when determining whether a function overrides another, so even in
// Redundant private for clarity:
class A { private: virtual void foo(); };
class B : A { public: void foo(); };
B::foo overrides A::foo.
During compile time C++ compiler verifies accessibility of functions and methods based on their type. In function C variable g is of type A (checked during compilation of the code), in which method f is declared as public.
Take a look at this link
I'm aware of the uses of private (and of course public) destructors.
I'm also aware of the uses of a protected destructor in a derived class:
Use a protected destructor to prevent the destruction of a derived object via a base-class pointer
But I've tried running the following code and it won't compile:
struct A{
int i;
A() { i = 0;}
protected: ~A(){}
};
struct B: public A{
A* a;
B(){ a = new A();}
void f(){ delete a; }
};
int main()
{
B b= B();
b.f();
return 0;
}
I get:
void B::f()':
main.cpp:9:16: error: 'A::~A()' is protected
What am I missing?
If I called a protected method in A from inside f() it would work. So why is calling the d'tor different?
protected doesn't mean that your B can access the members of any A; it only means that it can access those members of its own A base... and members of some other B's A base!
This is in contrast to private, whereby some object with type A can always invoke the private members of another object with type A.
In C++, let's say I have a class Derived that implements an interface class BaseInterface, where BaseInterface has only pure virtual functions and a virtual destructor:
class BaseInterface
{
public:
virtual void doSomething() = 0;
~BaseInterface(){}
};
class Derived : public BaseInterface
{
public:
Derived() {}
~Derived(){}
protected:
virtual void doSomething();
private:
int x;
};
No classes outside the Derived class hierarchy should call Derived::doSomething() directly, i.e., it should only be accessed polymorphically through the BaseInterface class. To enforce this rule, I have made Derived::doSomething() protected. This works well, but I'm looking for opinions pro/con regarding this approach.
Thanks!
Ken
I think you're looking for the non-virtual interface (NVI) pattern: a public non-virtual interface that calls a protected or private virtual implementation:
class BaseInterface
{
public:
virtual ~BaseInterface(){}
void doSomething() { doSomethingImpl(); }
protected:
virtual void doSomethingImpl() = 0;
};
class Derived : public BaseInterface
{
public:
Derived() {}
virtual ~Derived(){}
protected:
virtual void doSomethingImpl();
private:
int x;
};
If it is part of the interface, why would you not want users to call it? Note that as it is, they can call it: static_cast<BaseInterface&>(o).doSomething() is just an awkward way of saying o.doSomething(). What is the point of using the interface... if the object fulfills the interface, then you should be able to use it, or am I missing something?
Since you are not actually blocking anyone from calling the methods, I don't see a point in making the code more complex (both the class and users of the class) for no particular reason. Note that this is completely different from the Non-Virtual Interface in that in this idiom virtual functions are not accessible publicly (at any level) while in your case, the intention is allowing access, and making it cumbersome.
What you are doing is also mentioned in standard ISO/IEC 14882:2003(E) 11.6.1 and believe you are correct. Other than the fact, the member function isn't pure virtual in the given example. It should hold for pure virtual functions too, AFAIK.
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.
[Example:
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
}
—end example]
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.
The key is the rest of your code. Only accept a BaseInterface* as an argument to any methods that require the doSomething() call. The client programmer is forced to derive from the interface to make his code compile.
This makes no sense to me. Regardless of which pointer you call doSomething(), you would still wind up with the method defined in most derived class. Consider the following scenario:
class BaseInterface
{
public:
virtual void doSomething() = 0;
~BaseInterface(){}
};
class Derived : public BaseInterface
{
public:
Derived() {}
~Derived(){}
virtual void doSomething(){}
private:
int x;
};
class SecondDerived : public Derived
{
public:
SecondDerived() {}
~SecondDerived(){}
private:
int x;
};
int main(int argc, char* argv[])
{
SecondDerived derived;
derived.doSomething(); //Derived::doSomething is called
BaseInterface* pInt = &derived;
pInt->doSomething(); //Derived::doSomething is called
return 0;
}