Confusion about ctor/dtor behavior with inherited classes - c++

Until today I thought I understood inheritance much better than I apparently do. The goal here with this example was to design a framework of n number of classes (3 in this case), which should each exist uniquely for the life of the program. The forth class, whose implementation would contain the global main function would be responsible handling memory for the other classes. In addition, I was hoping to keep public members in the base classes protected, to prevent any other class from calling them.
Currently, the inheritance in the "Main" class is commented out as well as "protected:" keywords in each of the base classes. It doesn't do exactly what I want but everything behaves like normal. Constructors are called once (in ascending order), each function is called followed by the destructor.
My confusion here is actually two fold. If you un-comment the inheritance in the Main class, the code compiles, but new each ctor/dtor is called twice, first in ascending order order and then descending order. I've been unable to reason why this would occur, but it doesn't seem correct. Every explanation of inheritance I have ever seen is vague and doesn't explain why this would need to happen.
class Main //: public A, public B, public C
My second point of confusion is the protected members of the classes. I would think that if I un-comment the "protected:" keywords, proceeding the methods in the base classes, I should be able to call them from the inherited classes. As I understand it, I should even be able to inherit them as private, assuming I only want the children to have this functionality. Alas, I just get error messages about the method being protected.
I'm well aware that my understanding has some major shortfalls, but I've been exhaustively searching for an explanation with no luck. I could really use some constructive insight in to what is going on here,
Thanks,
#include <iostream>
#include <memory>
using namespace std;
class A
{
public:
A() { cout << "Ctor A\n";}
~A() { cout << "Dtor A\n";}
//protected:
void func() { cout << "Function A\n"; }
};
class B
{
public:
B() { cout << "Ctor B\n";}
~B() { cout << "Dtor B\n";}
//protected:
void func() { cout << "Function B\n"; }
};
class C
{
public:
C() { cout << "Ctor C\n";}
~C() { cout << "Dtor C\n";}
//protected:
void func() { cout << "Function C\n"; }
};
class Main //: public A, public B, public C
{
public:
Main(A *a, B *b, C *c);
private:
std::unique_ptr<A> mA;
std::unique_ptr<B> mB;
std::unique_ptr<C> mC;
};
Main::Main(A *a, B *b, C *c) : mA(a), mB(b), mC(c)
{
mA->func();
mB->func();
mC->func();
}
int main()
{
Main m(new A, new B, new C);
return 0;
}
In case anyone is curious, I've been trying to compile this on ideone.com with the gcc v8.3 compiler.

If you un-comment the inheritance in the Main class, the code compiles, but new each ctor/dtor is called twice, first in ascending order order and then descending order. I've been unable to reason why this would occur, but it doesn't seem correct. Every explanation of inheritance I have ever seen is vague and doesn't explain why this would need to happen.
You have three calls to new. Then you construct a Main, which requires constructing an A, a B, and a C. Since an instance of a Main is an A, a B, and a C, those three constructors have to be called to construct valid instances of those three types.
I would think that if I un-comment the "protected:" keywords, proceeding the methods in the base classes, I should be able to call them from the inherited classes.
Sure, but not on an arbitrary instance of the class that isn't even of the derived type! You have:
mA->func();
This is in a member function of class Main, but is operating on something that isn't an instance of class Main. The class Main has special access to itself as an instance of class A -- its internal interface can use protected functions of itself as an instance of class A, but that's it.

Related

Private inheritance causing problem in c++ [duplicate]

This question already has answers here:
private inheritance
(6 answers)
What is the difference between public, private, and protected inheritance in C++?
(16 answers)
Closed 3 years ago.
Why would the following code run into error of ‘A’ is an inaccessible base of ‘B’? Here's my thoughts:
whenever we call function foo(), it will execute new B(5), which will first call the constructor of its base struct A.
struct A's constructor function is a public method, hence it should be accessible by its derived struct B (as protected if i'm not wrong).
then struct B's constructor function will be call to create a vector with five 0s.
then deleting object a will call destructor B, then destructor A.
Is there anything wrong with my logic? Your answer will be greatly appreciated
#include <iostream>
#include <vector>
using namespace std;
struct A
{
A() { cout << "Constructor A called"<< endl;}
virtual ~A() { cout << "Denstructor A called"<< endl;}
};
struct B : private A
{
vector<double> v;
B(int n) : v(n) { cout << "Constructor B called"<< endl;}
~ B() { cout << "Denstructor B called"<< endl;}
};
int main()
{
const A *a = new B(5);
delete a;
return 0;
}
There's nothing wrong with your logic, except that it's missing one point:
private inheritance basically means that only the inheriting class (B in this case) knows that it inherits from the base A.
That in turn means that only B can make use of all the privileges that come with this inheritance. One of these privileges is to be able to cast B* to A*. The function foo() doesn't know about B's inheritance, so it cannot perform that cast.
TL;DR
You are deriving B as 'private' from A. You must change it to
struct B : public A{
vector<double> v;
B(int n): v(n) {std::cout << "B Constructor" << std::endl};
~B() {std::cout << "B Destruktor" << std:.endl;};
};
Extended explanation
By using private inheritance you define B has a A instead of B is a A. With a has-a dependency you cannot up- and downcast between both classes (Apple cannot become a worm and vice versa. Even if an apple has a worm).
You mainly use private inheritance if you want to take advante of features implemented by another class, without exposing the public Inteface of the used class. For e.g. You could use features of a parser inside your class without being a parser on your own.

Create a class that contains all functions of its parent class except one

Suppose I have two classes,
one is:
class A{
public:
void f1()
{
cout << "function 1";
}
void f2()
{
cout << "function 2";
}
void f3()
{
cout << "function 3";
}
};
Now I want class B to contain all the functions of A except f3.
what I am doing is:
class B: public A
{
private:
void f3()
{
}
};
According to my knowledge, B::f3() is hiding the definition of A::f3(), and as B::f3() is private, f3() is not accessible via class B. But what I can still do is call it like this:
B var();
var.A::f3();
Is there any way I could completely hide f3 from class B using inheritance and without changing class A?
Don't get in the habit of piecing classes together through inheritance by mixing and matching classes that do roughly what you want. That leads to awful code.
However, occasionally it does make sense to implement one class by means of another. In those cases, if you are using inheritance, the "correct" way to do it is by using private inheritance.
And by "correct" I mean the most acceptable way.
class A
{
public:
void f1()
{
cout << "function 1";
}
void f2()
{
cout << "function 2";
}
void f3()
{
cout << "function 3";
}
};
class B: private A
{
public:
using A::A; // use A's constructors
using A::f1;
using A::f2;
// do not use f3
};
The times when this may make sense is when composition is way too tedious because of the number of methods involved.
You should not make B inherit from A.
If B lacks some functionality of A, then B and A do not have the is-a relationship that inheritance is intended to model (and which clients will expect). You should use composition instead: introduce a member of B of type A.
You may cheat with private inheritance
class B : private A
{
public:
using A::f1;
using A::f2;
};

Missunderstanding in virtual function call

I have the following code, and I don't understand why it calls the A class function instead of B class function. Could someone tell me why??
#include<iostream>
using namespace std;
class A{
public:
virtual void f(int n){
f(n);
cout << "A";
}
};
class B :public A{
public:
virtual void f(float f){
cout << "B";
}
};
int main(){
A*p= new B;
p->f(5.1);
}
These are completely different functions. A function is identified by its name and its arguments. You have no overriding here: you have two distinct functions.
If you'd used the override keyword, the compiler would have immediately told you this.
I Modified your Code slightly as under. And I get the desired result.
i.e.: when accessing a derived class reference from a base class pointer I get the compiler to map my function call correctly to the derived class' implementation.
I guess the following facts apply:
A derived class would have to first implement(override: which doesn't say change the signature) the Virtual functions defined by the base class to be able to call/access them polymorphically.
After a base class has implemented the virtual functions they can very well be overloaded.
One other thing, If we see the VTable creation mechanism, Only when the derived class implements a virtual function defined at a base calss an entry for the same function name would be made. Otherwise the pointer A is still a map of the Class A and has no idea how to resolve the call to and ends up in implicitly casting the 5.1 double to int according to the implementation of function f in class A. this is pretty much what I mentioned in point#1
virtual functions and pure virtual functions are a means of providing/creating an interface which can be shared across different layers of your software, where the you simply share the interface and the can hide the implementation from the user. So having same function name/ interfaces defined by two classes would only cause more confusion.
#include<iostream>
using namespace std;
class A{
public:
virtual void f(int n){ cout << "A" << endl; }
};
class B :public A{
public:
void f(int f){ cout << "B" << endl; }
void f(float f){ cout << "B" << endl; }
};
int main(){
A*p= new B;
p->f(5.1);
}
Since there are lot of pros in this forum, ff there is anything incorrect in my answer, please put in your comments.
Thanks.

Friendliness and inheritance

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.

Multiple inheritance + virtual function mess

I have a diamond multiple inheritance scenario like this:
A
/ \
B C
\ /
D
The common parent, A, defines a virtual function fn().
Is it possible for both B and C to define fn()?
If it is, then the next question is - can D access both B and C's fn() without disambiguation? I'm assuming there is some syntax for this..
And is it possible for D to do that without knowing specifically who are B and C? B and C can be replaces by some other classes and I want the code in D to be generic.
What I'm trying to do is to have D somehow enumerate all of the instances of fn() it has in its ancestry. Is this possible in some other means that virtual functions?
Unless you overwrite fn again in D, no it is not possible. Because there is no final overrider in a D object: Both C and B override A::fn. You have several options:
Drop either C::fn or B::fn. Then, the one that still overrides A::fn has the final overrider.
Place a final overrider in D. Then, that one overrides A::fn aswell as fn in C and B.
For example the following results in a compile time error:
#include <iostream>
class A {
public:
virtual void fn() { }
};
class B : public virtual A {
public:
virtual void fn() { }
};
class C : public virtual A {
public:
virtual void fn() { }
};
// does not override fn!!
class D : public B, public C {
public:
virtual void doit() {
B::fn();
C::fn();
}
};
int main(int argc, char **argv) {
D d;
d.doit();
return 0;
}
You can, however derive non-virtual from A in C and B, but then you have no diamond inheritance anymore. That is, each data-member in A appears twice in B and C because you have two A base-class sub-objects in an D object. I would recommend you to rethink that design. Try to eliminate double-objects like that that require virtual inheritance. It often cause such kind of conflicting situations.
A case very similar to this is when you want to override a specific function. Imagine you have a virtual function with the same name in B and C (now without a common base A). And in D you want to override each function but give different behavior to each. Depending whether you call the function with a B pointer or C pointer, you have the different behavior. Multiple Inheritance Part III by Herb Sutter describes a good way of doing that. It might help you decide on your design.
First question, yes, B and C can define fn() as a virtual function.
Second, D can of course access B::fn() and C::fn() by using the scope operator ::
Third question: D must at least know B and C, since you have to define them on the inheritance list. You can use templates to let the types of B and C open:
class A
{
public:
virtual ~A() {}
virtual void fn() = 0;
};
class B: public A
{
public:
virtual ~B() {}
virtual void fn(){ std::cout << "B::fn()" << std::endl; }
};
class C: public A
{
public:
virtual ~C() {}
virtual void fn(){ std::cout << "C::fn()" << std::endl; }
};
template <typename TypeB, typename TypeC>
class D: public TypeB, public TypeC
{
public:
void Do()
{
static_cast<TypeB*>(this)->fn();
static_cast<TypeC*>(this)->fn();
}
};
typedef D<B, C> DInst;
DInst d;
d.Do();
About the wish to automatically enumerate all fn() functions of all classes that D inherits from: I'm not sure if that is possible without resorting to MPL. At least you can extend my example above with versions that deal with 3 and more template parameters, but I guess there is an upper (internal compiler-)limit of number of class template parameters.
You cannot enumerate the definitions of fn() in the ancestry. C++ lacks reflection. The only way I can imagine is a giant loop testing the typeid's of all possible ancestors. And it hurts to imagine that.
You might want to look at Loki TypeLists if you really need to be able to track ancestry and enumerate through types. I'm not sure if what you are asking for is really possible without a bunch of work. Make sure that you aren't over-engineering here.
On a slightly different note, if you are going to use MI in this manner (i.e., the dreaded diamond), then you should be very explicit about which virtual member you want. I can't think of a good case where you want to choose the semantics of B::fn() over C::fn() without explicitly making a decision when writing D. You will probably pick one over the other (or even both) based on what the individual method does. Once you have made a decision, the requirement is that inherited changes do not change the expectations or semantic interface.
If you are really worried about swapping in a new class, say E in place of say B where E does not descend from B but offers the same interface, then you should really use the template approach though I'm not sure why there is a static_cast<> in there...
struct A {
virtual ~A() {}
virtual void f() = 0;
};
struct B: A {
virtual void f() { std::cout << "B::f()" << std::endl; }
};
struct C: A {
virtual void f() { std::cout << "C::f()" << std::endl; }
};
template <typename Base1, typename Base2>
struct D: Base1, Base2 {
void g() { Base1::f(); Base2::f(); }
};
int main() {
D<B,C> d1;
D<C,B> d2;
d1.g();
d2.g();
return 0;
}
// Outputs:
// B::f()
// C::f()
// C::f()
// B::f()
works fine and seems a little easier to look at.
Vividos has already answered the main part of the post. Even if I would use the scope operator instead of the more cumbersome static_cast<> + dereference operator.
Depending on the task at hand, maybe you can change the inheritance relationship from D to B and C for a less coupling composition (plus possibly inheritance from A). This is assuming that you don't need D to be used polimorphically as either B or C, and that you don't really require B and C sharing the same base instance.
If you opt for composition, you can receive the B and C as arguments to your constructor as references/pointers of type A, making D completely unaware of the types B and C. At that point, you can use a container to hold as many A derived objects. Your own implementation of fn() (if you so decide) or any other method.
There are already several questions that deal with this. Seems like we're running out of questions to ask. Maybe the search box should be bigger than the Ask Question button.
See
How can I avoid the Diamond of Death when using multiple inheritance?
What is the exact problem with multiple inheritance?
Is Multiple Inheritance Evil?