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.
Related
There is no explicit destructor in base class. Then, I delete the derived class with derived pointer. After that, if I access the member of the derived class, the crash happened. However, if I access the base member, the program still ok. Why?
class Base {
public:
virtual void doSomething() = 0;
protected:
virtual ~Base() {} // if I remove the destructor, then the program still run ok even if I remove the derived class.
};
class Derived: public Base {
public:
Derived() {}
~Derived() {}
void doSomething() override { a_ = true; }
private:
bool a_;
};
Derived *pD = new Derived();
Base *pB = static_cast<Base*>(pD);
delete pD;
pB->doSomething(); // the program is ok if I remove the destructor in base class
pD->doSomething(); // the program crash no matter the destructor of base class is there or not.
if I access the member of derived class, the crash happpend.
if I access the base member, the program still ok. Why?
Because the behaviour of accessing through an invalid pointer is undefined.
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!
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 ]
Is it ok to delete an abstract class instead of a child? Will all allocs be deallocated thereby?
Consider a following situation as an example, but please do not limit your answers to that one case:
struct A {
virtual void fun() = 0;
};
struct B : public A {
void fun() { /* actually doing something here. */ }
};
struct C {
A *a;
void OneTask() {
// (...)
a = new B();
}
void AnotherTask() { /* using fun() in some way. */ }
~C() { delete a; }
};
The idea is to have multiple possible outcomes of OneTask() which result in an assignment of a pointer to different classes that inherit from A, B being just an example; and then to use such result reasonably in AnotherTask() and other methods of class C.
You must have virtual destructor in base class else complete destruction of derived class doesn't happen.
struct A {
virtual void fun() = 0;
virtual ~A()
{
}
};
Yes, it's perfectly fine to delete a without knowing what actual derived type a is pointing to.
As shivakumar pointed out, if you don't make your base class's destructor virtual, then deleting a derived class will not end up calling the base class's destructor. In your trivial example that's not a problem, but in real life you should always make your destructors virtual.
If A has a virtual destructor then both destructors of A and B are succesfully called (first B then A) ,
If you do not declare the constructor of A as virtual, then only the destructor of A is called during deletion and extended data of B may leak.
struct A {
virtual void fun() = 0;
virtual ~A();
};
struct B : public A {
void fun() { /* actually doing something here. */ }
~B();
};
#include <iostream>
using namespace std;
class base{
public:
int i;
base(){
i=1;
cout<<"Base Constructor";
}
};
class derived: private base{
public:
derived(){
i=2;
cout<<"Derived constructor";
}
};
int main(){
derived c;
return 0;
}
For the above code why am I getting the output as
"Base ConstructorDerived Constructor"
even though I inherited using private?
Why am I still be able to access it from main function?
You aren't.
Your main function accesses derived's constructor, which it has access to.
And derived's constructor accesses base's constructor, which it has access to.
A constructor automatically initializes the base classes and the members before executing the body of the constructor. Private inheritance doesn't change that. It just makes the base part of the class not accessible outside the class. Since it is the derived class constructor that is calling the base class constructor, the private inheritance doesn't restrict what it can do.
What you mean to do is make the constructor of the base class protected. Then only derived classes can use it:
class base
{
protected:
base() : i(1) { }
private:
int i;
};
class derived : private base
{
public:
derived() : base() { }
};
int main()
{
// base b; // error: inaccessible constructor base::base()
derived d; // fine
}
A somewhat popular pattern is also to make the destructor protected. You get the point, though.