Suppose i have this code:
#include <iostream>
using namespace std;
class A
{
protected:
virtual ~A() { cout << "A destructor reached." << endl;}
friend class Z;
};
class B : public A
{
protected:
virtual ~B() { cout << "B destructor reached." << endl; }
};
class Z
{
public:
void Test();
friend class A;
};
void Z::Test()
{
A* derived = (A*) new B();
delete derived;
}
int main()
{
Z test;
test.Test();
}
What is going to happen, will the B destructor be called? Is it legal? And if it's not, is there any way to call the derived constructor without making every class derived from A friend of Z?
The Standard, §11.5/1 "access to virtual functions," says
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.
So you can call B::~B as long as you have access to A::~A. But you must call it through A because Z does not have access to B.
By the way, the friend declaration in Z is useless since nothing is private or protected in it.
There are at least two questions involved here.
Yes, B's destructor will be called. That's how polymorphism works, that's how virtual destructors work, it's by design and it's a good thing.
The fact that a member function that is protected (or even private) in B but virtual and available (e.g. public) in A can be invoked via A* may seem a little odd at first, but it's by design too. What's the alternative? The only other option I can see would be to forbid inheritance that increases the restriction of a virtual member function; what good purpose would that serve?
If you don't want a method to be accessible, don't derive it from an accessible virtual parent method.
Related
So I recently accidentally called some virtual functions from the constructor of a base class, i.e. Calling virtual functions inside constructors.
I realise that I should not do this because overrides of the virtual function will not be called, but how can I achieve some similar functionality? My use-case is that I want a particular function to be run whenever an object is constructed, and I don't want people who write derived classes to have to worry about what this is doing (because of course they could call this thing in their derived class constructor). But, the function that needs to be called in-turn happens to call a virtual function, which I want to allow the derived class the ability to override if they want.
But because a virtual function gets called, I can't just stick this function in the constructor of the base class and have it get run automatically that way. So I seem to be stuck.
Is there some other way to achieve what I want?
edit: I happen to be using the CRTP to access other methods in the derived class from the base class, can I perhaps use that instead of virtual functions in the constructor? Or is much the same issue present then? I guess perhaps it can work if the function being called is static?
edit2: Also just found this similar question: Call virtual method immediately after construction
If really needed, and you have access to the factory.
You may do something like:
template <typename Derived, typename ... Args>
std::unique_ptr<Derived> Make(Args&&... args)
{
auto derived = std::make_unique<Derived>(std::forward<Args>(args));
derived->init(); // virtual call
return derived;
}
There is no simple way to do this. One option would be to use so-called virtual constructor idiom, hide all constructors of the base class, and instead expose static 'create' - which will dynamically create an object, call your virtual override on it and return (smart)pointer.
This is ugly, and what is more important, constrains you to dynamically created objects, which is not the best thing.
However, the best solution is to use as little of OOP as possible. C++ strength (contrary to popular belief) is in it's non-OOP specific traits. Think about it - the only family of polymorphic classess inside standard library are streams, which everybody hate (because they are polymorphic!)
I want a particular function to be run whenever an object is constructed, [... it] in-turn happens to call a virtual function, which I want to allow the derived class the ability to override if they want.
This can be easily done if you're willing to live with two restrictions:
the constructors in the entire class hierarchy must be non-public, and thus
a factory template class must be used to construct the derived class.
Here, the "particular function" is Base::check, and the virtual function is Base::method.
First, we establish the base class. It has to fulfill only two requirements:
It must befriend MakeBase, its checker class. I assume that you want the Base::check method to be private and only usable by the factory. If it's public, you won't need MakeBase, of course.
The constructor must be protected.
https://github.com/KubaO/stackoverflown/tree/master/questions/imbue-constructor-35658459
#include <iostream>
#include <utility>
#include <type_traits>
using namespace std;
class Base {
friend class MakeBase;
void check() {
cout << "check()" << endl;
method();
}
protected:
Base() { cout << "Base()" << endl; }
public:
virtual ~Base() {}
virtual void method() {}
};
The templated CRTP factory derives from a base class that's friends with Base and thus has access to the private checker method; it also has access to the protected constructors in order to construct any of the derived classes.
class MakeBase {
protected:
static void check(Base * b) { b->check(); }
};
The factory class can issue a readable compile-time error message if you inadvertently use it on a class not derived from Base:
template <class C> class Make : public C, MakeBase {
public:
template <typename... Args> Make(Args&&... args) : C(std::forward<Args>(args)...) {
static_assert(std::is_base_of<Base, C>::value,
"Make requires a class derived from Base");
check(this);
}
};
The derived classes must have a protected constructor:
class Derived : public Base {
int a;
protected:
Derived(int a) : a(a) { cout << "Derived() " << endl; }
void method() override { cout << ">" << a << "<" << endl; }
};
int main()
{
Make<Derived> d(3);
}
Output:
Base()
Derived()
check()
>3<
If you take a look at how others solved this problem, you will notice that they simply transferred the responsibility of calling the initialization function to client. Take MFC’s CWnd, for instance: you have the constructor and you have Create, a virtual function that you must call to have a proper CWnd instantiation: “these are my rules: construct, then initialize; obey, or you’ll get in trouble”.
Yes, it is error prone, but it is better than the alternative: “It has been suggested that this rule is an implementation artifact. It is not so. In fact, it would be noticeably easier to implement the unsafe rule of calling virtual functions from constructors exactly as from other functions. However, that would imply that no virtual function could be written to rely on invariants established by base classes. That would be a terrible mess.” - Stroustrup. What he meant, I reckon, is that it would be easier to set the virtual table pointer to point to the VT of derived class instead of keep changing it to the VT of current class as your constructor call goes from base down.
I realise that I should not do this because overrides of the virtual function will not be called,...
Assuming that the call to a virtual function would work the way you want, you shouldn't do this because of the invariants.
class B // written by you
{
public:
B() { f(); }
virtual void f() {}
};
class D : public B // written by client
{
int* p;
public:
D() : p( new int ) {}
void f() override { *p = 10; } // relies on correct initialization of p
};
int main()
{
D d;
return 0;
}
What if it would be possible to call D::f from B via VT of D? You will use an uninitialized pointer, which will most likely result in a crash.
...but how can I achieve some similar functionality?
If you are willing to break the rules, I guess that it might be possible to get the address of desired virtual table and call the virtual function from constructor.
Seems you want this, or need more details.
class B
{
void templateMethod()
{
foo();
bar();
}
virtual void foo() = 0;
virtual void bar() = 0;
};
class D : public B
{
public:
D()
{
templateMethod();
}
virtual void foo()
{
cout << "D::foo()";
}
virtual void bar()
{
cout << "D::bar()";
}
};
#include<iostream>
class base
{
public:
virtual ~base(){std::cout << "base\n";}
};
class derived : public base
{
private:
~derived(){std::cout << "derived\n";} /* destructor is private */
};
int main()
{
base *pt= new derived;
delete pt;
}
The above program compiles and runs fine.
How does the derived class destructor get invoked being private ?
This will happen not only with destructors.
You can override any virtual public function with a private one.
#include<iostream>
class base
{
public:
virtual void x(){std::cout << "base\n";}
};
class derived : public base
{
private:
void x(){std::cout << "derived\n"; base::x();}
};
int main()
{
base *pt= new derived;
pt->x(); //OK
//((derived *)pt)->x(); //error: ‘virtual void derived::x()’ is private
derived *pt2= new derived;
//pt2->x(); //error: ‘virtual void derived::x()’ is private
((base *)pt2)->x(); //OK
}
Upside/downside of this is you will have to use pointer to base to access this method.
This feature is one of ways to separate public API from customized implementation.
So, in other words, your destructor is getting called because it was declared as public in base and you are calling it trough pointer to base.
That may be surprising, but if you think about it, it's perfectly logical.
What the compiler sees is that you delete a pointer-to-base, which has an accessible destructor. So it has no reason to complain about what you're doing. Incidentially, it's a virtual destructor, but that's not something to complain about either.
At runtime, the virtual destructor is invoked. Since it turns out that the pointer-to-base is really pointing at a derived object, consequently the derived constructor needs to be invoked first.
"But that one is private!" says you. That's right, however, there is no notion of public/private during runtime. So, again, there is no reason for anything bad to happen. No error is generated.
Yesterday, I wrote some code and i would really appreciate a judgement if this is good or bad practice. And if its bad, what could go wrong.
The construct is as followed:
The base class A comes from an API sadly as a template. The goal was to be able to put derived classes from A in a std::vector. I achieved this with the base class B from which all derived classes that inherit from A will inherit. Without the pure-virtual function in B the foo() function from A was called.
With the pure-virtual function in B the foo() version from C get called. This is exactly what I want.
So is this bad practice?
EDIT:
To clear some misunderstandings in my example code out:
template <class T>
class A
{
public:
/* ctor & dtor & ... */
T& getDerived() { return *static_cast<T*>(this); }
void bar()
{
getDerived().foo(); // say whatever derived class T will say
foo(); // say chicken
}
void foo() { std::cout << "and chicken" << std::endl; }
};
class B : public A<B>
{
public:
/* ctor & dtor */
virtual void foo() = 0; // pure-virtual
};
class C : public B
{
public:
/* ctor & dtor */
virtual void foo() { std::cout << "cow"; }
};
class D : public B
{
public:
/* ctor & dtor */
virtual void foo() { std::cout << "bull"; }
};
The std::vector shall contain both, C as well as D and
void main()
{
std::vector<B*> _cows;
_cows.push_back((B*)new C()));
_cows.push_back((B*)new D()));
for(std::vector<B*>::size_type i = 0; i != _cows.size(); ++i)
_cows[i].bar();
}
with output
cow and chicken
bull and chicken
is desired.
As far as I know is there no other way to store classes derived from a template class in a container than the use of a base class. If I use a base class for my derived classes, e.g., B i must cast every instance within the vector back to its proper class. But at the time bar() is called, I don't know the exact type.
I call it bad practice for doing possibly confusing and obfuscating things.
1) A function name should in all base and sub-classes either be virtual or non-virtual.
mixing overriding and overloading within the inheritance hierachry is a very bad idea.
No one really expects something like that.
Thus if A::foo should be virtual as well, or B and C foo should not.
2) Preferably base classes should be interfaces.
As such A:foo should be pure virtual and not B::foo.
2b) If a base class has already provided a default implementation don't declare the function pure virtual in a sub-class.
I came across a question while taking iKM test. There was a base class with two abstract methods with private access specifier. There was a derived class which was overriding these abstract methods but with protected/public access specifier.
I never came across such thing where overridden methods in derived class had different access specification. Is this allowed ? If yes, does it comply to "IS A" relation between base and derived (i.e. safely substitutable).
Could you point me to some references which can provide more details on such usages of classes ?
Thank you.
It is allowed, in both directions (ie, from private to public AND from public to private).
On the other hand, I would argue it does not break the IS-A relationship. I base my argument on 2 facts:
using a Base& (or Base*) handle, you have exactly the same interface as before
you could perfectly (if you wish) introduce a forward method that is public and calling the private method directly anyway: same effect with more typing
Yes, this is legal, accessibility is checked statically (not dynamically):
class A {
public:
virtual void foo() = 0;
private:
virtual void bar() = 0;
};
class B : public A {
private:
virtual void foo() {} // public in base, private in derived
public:
virtual void bar() {} // private in base, public in derived
};
void f(A& a, B& b)
{
a.foo(); // ok
b.foo(); // error: B::foo is private
a.bar(); // error: A::bar is private
b.bar(); // ok (B::bar is public, even though A::bar is private)
}
int main()
{
B b;
f(b, b);
}
Now, why would you want to do that? It only matters if you use the derived class B directly (2nd param of f()) as opposed to through the base A interface (1st param of f()).
If you always use the abstract A interface (as I would recommend in general), it still complies to the "IS-A" relashionship.
As many of the guys pointed out it is legal.
However, "IS-A" part is not that simple. When it comes to "dynamic polymorphism" "IS-A" relation holds, I.e. everything you can do with Super you can also do with Derived instance.
However, in C++ we also have something that is often referred as static polymorphism (templates, most of the time). Consider the following example:
class A {
public:
virtual int m() {
return 1;
}
};
class B : public A {
private:
virtual int m() {
return 2;
}
};
template<typename T>
int fun(T* obj) {
return obj->m();
}
Now, when you try to use "dynamic polymorphism" everything seems to be ok:
A* a = new A();
B* b = new B();
// dynamic polymorphism
std::cout << a->m(); // ok
std::cout << dynamic_cast<A*>(b)->m(); // ok - B instance conforms A interface
// std::cout << b->m(); fails to compile due to overriden visibility - expected since technically does not violate IS-A relationship
... but when you use "static polymorphism" you can say that "IS-A" relation no longer holds:
A* a = new A();
B* b = new B();
// static polymorphism
std::cout << fun(a); // ok
//std::cout << fun(b); // fails to compile - B instance does not conform A interface at compile time
So, in the end, changing visibility for method is "rather legal" but that's one of the ugly things in C++ that may lead you to pitfall.
Yes, this is allowed as long as the signature is the same. And in my opinion, yes, you're right, overriding visibility (for example, public -> private) breaks IS-A. I believe Scott Myers Effective C++ series has a discussion on this one.
class A {
public:
A() { }
~A() { cout << "A Destructor \n" ; }
};
class B :public A{
public:
B() { }
virtual ~B() { cout << "B Destructor \n" ; }
};
class C : public B {
public:
C() { }
~C() { cout << "C Destructor \n"; }
};
int main()
{
A *pointA = new A;
A *pointB = new B;
A *pointC = new C;
delete pointA;
delete pointB;
delete pointC;
}
It will invoke undefined behavior at the second (and third) delete, because A's destructor is not virtual.
§5.3.5/3:
if the static type of the operand is different from its dynamic type, the
static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined.
If you make the destructor of A virtual, you get well-defined behavior, and the destructor of the dynamic type is called. (And each of those in turn calls the base destructor.) Your output would be:
A destructor
B destructor
A destructor
C destructor
B destructor
A destructor
For what it's worth, when you're that close to a compilable snippet, you should leave the includes. Also, just use struct instead of class to be concise about the public stuff, and leave out empty constructors.
As GMan pointed out, attempting to call the delete operator on a base pointer requires a virtual destructor for the compiler to be able to destroy subclass objects correctly. A lot of people oversimplify this to a rule like, "If a class has virtual functions, it needs a virtual destructor." That is not necessarily the case; even a base class which has no virtual functions still needs a virtual destructor if you want to allow clients to delete the class through a base pointer. If you don't, the destructor should be protected and not public.
There is an excellent book that describes this in detail and more called C++ Coding Standards by Herb Sutter. I recommend it as a starting point in your C++ adventures. :-)