Eliminating C++ diamond inheritance by passing a pointer to "this" to base constructor - c++

I understand how C++ solves the diamond problem in multiple inheritance by using virtual inheritance. Suppose the following situation:
class A {
int num;
public:
int get_num() const { return num; }
};
class B : public A {
void foob() { int x = get_num(); }
};
class C : public A {
void fooc() { int x = get_num(); }
};
class D : public B, public C {
void food() { int x = get_num(); }
};
The get_num() call is ambiguous inside food(). I know I can fix it either by calling A::get_num() or by virtual inheritance using virtual public A. But I can see a third approach:
class A {
int num;
public:
int get_num() const { return num; }
};
class B : public A {
void foob() { int x = get_num(); }
};
class C { // won't inherit from A anymore
const A& base; // instead keeps a reference to A
void fooc() { int x = base.get_num(); }
public:
explicit C(const A* b) : base(*b) { } // receive reference to A
};
class D : public B, public C {
void food() { int x = get_num(); }
public:
D() : C(this) { } // pass "this" pointer
};
The external code doesn't need to consider C as an A.
Considering it has no impacts on my particular class hierarchy design, are there any advantages of the third approach over the virtual inheritance way? Or, in terms of cost, it ends up being the same thing?

Congratulations ! You've just re-invented the principle of composition over inheritance !
If this works with your design, it means that C was in fact not a kind of A, and there was no real justification to use inheritance in first place.
But don't forget the rule of 5 ! While your approach should work in principle, you have a nasty bug here : with your current code, if you copy a D object, its clone uses the wrong reference to the base (it doesn't refer to it's own base, which can lead to very nasty bugs...
Demo of the hidden problem
Let's make A::get_num() a little bit more wordy, so that it tells us about the address of the object that invokes it:
int get_num() const {
cout << "get_num for " << (void*)this <<endl;
return num;
}
Let's add a member function to C, for the purpose of the demo:
void show_oops() { fooc(); }
And same for D:
void show() { food(); }
Now we can experiment the problem by running this small snippet:
int main() {
D d;
cout<<"d is "<<(void*)&d<<endl;
d.show();
d.show_oops();
D d2=d;
cout<<"d2 is "<<(void*)&d2<<endl;
d2.show();
d2.show_oops();
}
Here an online demo. You will notice that d2 does produce inconsistent results, like here:
d is 0x7fffe0fd11a0
get_num for 0x7fffe0fd11a0
get_num for 0x7fffe0fd11a0
d2 is 0x7fffe0fd11b0
get_num for 0x7fffe0fd11b0
get_num for 0x7fffe0fd11a0 <<< OUCH !! refers to the A element in d !!
Not only do you refer to the wrong object, but if the d object would decease, you would have a dangling reference, so UB.

Related

Calling overridden function and using overloaded variable from base class

I have two base classes and derivered versions that overload / override certain parts like this:
class base
{
public:
int X = 1;
};
class deriv : public base
{
public:
int X = 2;
};
class A
{
public:
base K;
virtual void doSmth()
{
std::cout << "A" << std::endl;
smthElse();
}
virtual void smthElse()
{
std::cout << K.X << std::endl;
}
};
class B : public A
{
public:
deriv K;
void doSmth()
{
std::cout << "B" << std::endl;
smthElse();
}
};
the application looks like this
int main()
{
A instanceA;
B instanceB;
instanceA.doSmth();
instanceB.doSmth();
getchar();
return 0;
}
And the output therefore is X=1 for both instances A and B. I was wondering why that is.
A uses base (X=1) and B uses deriv (X=2). deriv overloads X and B overloads K. Is this because the function smthElse() is only defined in A, thus A can't know about the existance of the overloaded variable K?
If so, is there a way for the function smthElse() to use the overloaded variable K?
I found the using keyword but also adding a using A::smthElse; in B won't change the behaviour of X not being printed as 2. The only way I can achieve this is by copying the function smthElse() from A and insert it into B.
Is there a different way to achieve what I'm looking for? Since it seems like an overkill to copy'n'paste the same function into B just to use an overridden variable.
Thanks in advance!
instanceB has two variables named K, A::K and B::K. However, the base class, A, only knows about one K, A::K.
That explains the output.
If so, is there a way for the function smthElse() to use the overloaded variable K?
Yes, you can do that by adding a virtual function in A that returns a reference to base and adding a virtual function in base that returns a reference to i.
class base
{
public:
int& getX( return X;}
private:
int X = 1;
};
class deriv : public base
{
public:
int& getX( return X;}
private:
int X = 2;
};
class A
{
public:
base& getK() { return K; }
virtual void doSmth()
{
std::cout << "A" << std::endl;
smthElse();
}
virtual void smthElse()
{
std::cout << getK().getX() << std::endl;
// ^^^^^^^^^^^^^ use the virtual functions
}
public:
base K;
};
class B : public A
{
public:
deriv& getK(){ return K; }
void doSmth()
{
std::cout << "B" << std::endl;
smthElse();
}
public:
base K;
};
PS I hope this is just curiosity and you don't write production code with such style. You will end up confusing yourself and anybody who tries to understand your code.
When you write
virtual void smthElse()
{
std::cout << K.X << std::endl;
}
smthElse is virtual
K is not (a member variable could not be virtual: it has no meaning for an attribute).
In other terms, it means that B::smthElse will ovevrride A::smthElse but B::K and A::K are two distinct, unrelated and independent variables.
When smthElse is called in the context of a B, K still means A::K.
As a solution, you might create a virtual accessor to Ks:
class base { ...};
class deriv{ ...};
class A
{
base K;
public:
virtual const base& theK() { return K; }
virtual void smthElse() { std::cout << theK().X << "\n"; }
};
class B : public A
{
deriv K;
public:
virtual const base& theK() { return K; }
};
When B{}.smthElse() is called, it will call B::theK() which will return B::K (a deriv instance).

Create Function taking base class pointer but calling derived class function

I have two classes A (base) and B (deriving from A):
class A { };
class B : public A
{
int data;
public:
int get_data() { return data; }
};
Now I have a function test which takes base class pointer and calls derived class function :
void test(A * ptr)
{
ptr->get_data();
}
But problem is ptr may point to A's object or B's object. If it points to B's object, then OK, but if to A's object, then it is a problem.
Moreover, I don't want to make get_data() virtual because data is not property of A's object.
How can I check if ptr points to B's object? One solution which I can think is dynamic_cast and check it for NULL. Is it the best solution or can I have a better solution ?
This means your test function is lying. It is saying that it will accept a pointer to any A object, even types derived from A, but the function won't actually work for anything other than B. You're much better off taking a B*:
void test(B* ptr)
{
ptr->get_data();
]
If you can change the interface of A and B (including adding virtual functions) and if you can re-shuffle the code in the test function you can use the "visitor pattern". Here's a sample using the better named Base and Derived classes:
class Visitor
{
public:
void Visit(Base * B)
{
}
void Visit(Derived * D)
{
int data = D->get_data();
}
};
class Base
{
public:
virtual void Accept(Visitor * V )
{
V->Visit(this);
}
};
class Derived: public Base
{
public:
int get_data()
{
return data;
}
virtual void Accept(Visitor * V )
{
V->Visit(this);
}
private:
int data;
};
This way you can iterate over your vector of Base*, call Accept of each element and know that only for Derived elements the get_data method will be called.
Inheritance models the is-a relationship. Clearly in your code B is not an A and inheritance is the wrong model. You mention in your comment that you have a vector which is being passed to an enclosing, bigger, function. I would suggest that one of the following would be a better fit:
1. std::vector<boost::any>
2. std::vector<boost::variant<A,B>>
Edit
Here's an example using boost variant:
class A
{
public:
void DoIt()
{
std::cout << "did it!" << "\n";
}
};
class B
{
public:
void GetIt()
{
std::cout << "got it!" << "\n";
}
};
typedef boost::variant<A,B> ab_t;
typedef std::vector<ab_t> list_ab;
void test(list_ab& list)
{
std::for_each(std::begin(list), std::end(list), [](ab_t& item)
{
if(A* a = boost::get<A>(&item))
a->DoIt();
if(B* b = boost::get<B>(&item))
b->GetIt();
});
}
You say that actually you have a vector of elements A or B, then your test function really looks like:
void test( A ** ptr )
Then you can use the overloading C++ capabilities to make a utility function, the right function will be called:
void test( A ** ptr ) {
A * elem;
int i=0;
elem = ptr[i++];
while(elem) {
testElement(elem);
elem = ptr[i++];
}
}
void testElement( A * ptr ) { }
void testElement( B * ptr ) {
ptr->get_data();
}

Constructor not called the expected number of times

Here is the code which causes a problem:
class Base
{
public:
virtual void fun()
{
cout<<"Base";
}
};
class Der:public Base
{
Base &pb;
public:
Der(Base&b):pb(b){}
virtual void fun()
{
cout<<"Der...";
pb.fun();
}
};
int main()
{
Der(Der(Base())).fun();
return 0;
}
Run this code,and the result shows "Der...Base..."! This is so amazing, I can't figure it out why the result is not "Der...Der...Base" which is logically right?!
Then I replace the member in class Der Base&pb with Base*pb and change the code into legal, finnaly the output is right which is "Der...Der...Base"!
I debug the code and find that when I use Base&pb, the constructor of Der only ran once while use Base*pb, the constructor ran twice correctly!
Any one who can explain to me what had happened and why?
In Der(Der(Base())).fun() expression the inner Der(Base()) yields an rvalue - the compiler optimizes the code by using copy elision and removes unnecessary copying of objects.
In addition to the #icepack's answer and the following discussion in the comments (summary: the code Der(der) is a cast, which may or may not be realized using constructor; in your case it's not), a workaround for you: you should make your intention clear by not using the constructor.
I would rewrite your code into something like this:
class Base
{
public:
virtual void fun()
{
cout<<"Base";
}
};
class Der:public Base
{
Base &pb;
Der(Base& b) : pb(b) {}
public:
static Der Decorate(Base&& b){ return Der(b); }
virtual void fun()
{
cout<<"Der...";
pb.fun();
}
};
int main()
{
Der::Decorate(Der::Decorate(Base())).fun();
return 0;
}
(outputs: Der...Der...Base).
Changing the code to accept the pointer is easy:
class Base
{
public:
virtual void fun()
{
cout << "Base";
}
};
class Der : public Base
{
Base* pb;
Der(Base* b) : pb(b) {}
public:
static Der Decorate(Base* b){ return Der(b); }
virtual void fun()
{
cout << "Der...";
pb->fun();
}
};
int main()
{
Der::Decorate(&Der::Decorate(&Base())).fun();
return 0;
}

Making sure the method declaration is inherited

How can I protect from accidental definition of non-inherited method where inherited definition is intended. I am told there is trick to express it, but nobody can recall it.
Explanation. I have tree of classes: 'Base' <- 'C' <- 'D', below. Base defines pure virtual function. The function gets redefined in C then in D. But the function has very long argument list.
Somewhere along chain of derivation, there is subtle error in the agrglist which makes D:: non-inherited. Program hapily compiles. And the wrong method is called in the run-time.
Is there trick to cause compilation error when method is non-inherited.
#include <iostream>
class Base {
public:
virtual void VeryLongFunctionName(int VeryLongArgumentList) = 0;
};
class C : public Base {
public:
void VeryLongFunctionName(int VeryLongArgumentList) {
std::cout << "C::\n";
}
};
class D : public C {
public:
void VeryLongFunctionNane(int VeryLongArgumentList) { // typo is intentional. It's the point of the question.
std::cout << "D::\n";
}
};
int main() {
Base *p = new D;
p->VeryLongFunctionName(0);
// the intention is to print D::. But it prints C::.
// How can we make compiler catch it.
return 0;
}
not exactly what you asked for, but i've used this form to reduce the chance for human error:
class t_very_long_argument_list {
public:
t_very_long_argument_list(T1& argument1, const T2& argument2);
/* ... */
T1& argument1;
const T2& argument2;
};
int C::VeryLongFunctionName(t_very_long_argument_list& arguments) {
std::cout << "C::\n";
}
For this exact purpose C++0x introduces the override member function decorator, as is already implemented in VC++ 2005 and later: http://msdn.microsoft.com/en-us/library/41w3sh1c.aspx
Alternatively, VC++ permits the following (presumably compiler-specific):
#include <iostream>
class Base {
public:
virtual void VeryLongFunctionName(int VeryLongArgumentList) = 0;
};
class C : public Base {
public:
void Base::VeryLongFunctionName(int VeryLongArgumentList) {
std::cout << "C::\n";
}
};
class D : public C {
public:
void Base::VeryLongFunctionNane(int VeryLongArgumentList) {
// ^^^^^^ now causes a compilation error
std::cout << "D::\n";
}
};
You have compilation errors -
int VeryLongFunctionName(int VeryLongArgumentList) supposed to return an int which none of the method definitions is doing so.
int VeryLongFunctionName(int VeryLongArgumentList) supposed to receive an int.
p->VeryLongFunctionName(); // Error
With these corrected, you should get the expected results. Check results : http://ideone.com/wIpr9

Passing around base class pointers

Scenario: I have the following defined classes.
class Baseclass { };
class DerivedTypeA : public Baseclass { };
class DerivedTypeB : public Baseclass { };
// ... and so on ...
class Container
{
list<Baseclass*> stuff;
list<DerivedTypeA*> specific_stuff;
// ... initializing constructors and so on ...
public:
void add(Baseclass * b)
{
stuff.add(b);
}
void add(DerivedTypeA * a)
{
stuff.add(a);
specific_stuff.add(a);
}
};
class ContainerOperator
{
Container c;
// ... initializing constructors and so on ...
public:
void operateOnStuff(Baseclass * b)
{
// This will always use "void add(Baseclass * b)" no matter what object b really is.
c.add(b);
}
};
// ...
containerOperator.operateOnStuff(new DerivedTypeA());
So, what I want to do is to handle a certain derived class in some special way in Container.
Problem: void add(DerivedTypeA * a) is never called. I'm obviously doing something wrong. What is the correct way of doing what I am trying to achieve here?
Overload resolution in C++ happens at compile-time, not run-time. The "usual" way to solve problems like this is to use Visitor pattern.
You can reduce the amount of boilerplate copy-paste by implementing Visitor with CRTP.
If you use CRTP for Base::accept, you don't need to define it any more in derived classes.
Here is a similar program to yours, but a little simpler:
#include <iostream>
class Base; class Derived;
struct Operation {
void add(Base *b) {
std::cout << "Base\n";
}
void add(Derived *b) {
std::cout << "Derived\n";
}
void visit(Base *b); // need to define this after Base class
};
struct Base {
virtual ~Base() {}
virtual void accept(Operation &o)
{
o.add(this);
}
};
void Operation::visit(Base *b) {
b->accept(*this);
}
struct Derived : public Base {
void accept(Operation &o)
{
o.add(this);
}
};
int main() {
Operation o;
Base b;
Derived d;
Base *ptrb = &b;
Base *ptrd = &d;
o.add(ptrb); // These two print "Base"
o.add(ptrd);
o.visit(ptrb); // "Base"
o.visit(ptrd); // "Derived"
}
You can use RTTI to determine whether the provided object is of the derived type, and if so, call the second add() function.
void add(Baseclass * b)
{
stuff.add(b);
DerivedTypeA * a = dynamic_cast<DerivedTypeA *>(b);
if ( a != 0 )
specific_stuff.add(a);
}
Unlike the visitor pattern this solution violates the Open-Closed Principle, but it's a lot simpler and easier to understand when the number of derived classes do not change or change slowly over time.