0

i'd like to discuss an inheritance problem in c++. The basic idea is to have a base class with properties and different child classes with accessors to this properties. And at the bottom shall be a class, which combines the child classes to one. It's a diamond shape, which introduces some problems.

class A {
public:
  A() { prop = 1; }
  int prop;
};

class B : public A {
public:
  int getProp() { return prop; }
private:
  B();
};

class C : public A {
public:
  int setProp(int v) { prop = v; }
private:
  C();
};

class D : public B, public C {
private:
  D();
};

usage() {
  A* a = new A();
  B* b = (B*)a; // Works
  b->getProp(); // Works
  D* d = (D*)a; // This fails, because of diamond inheritance
  d->setProp(5);// This is kindof the goal
  d->getProp();// This is kindof the goal
}

So, I've read something about virtual inheritance, but I cannot achieve the casting to D, which should include all methods of B and A. Maybe I'm missing something there.

On the other hand. I really have only functions in the classes B and C, so in general it would be possible to achieve these accessors via a static wrapper taking a instance of the class. But I'd like to ask you for ideas to actually achieve it without any wrappers, which take the original A as an argument.

Edit 1: I will provide you with some scenario to clarify what I am trying to achieve. Imagine Project A, B, C, D and E

Project_A contains Class_A. This class contains some member variables.
P_A also creates 5 instances of the class.
Project_C contains Class_C.
P_C also asks P_A to get the 5 instances of C_A.
P_C sets the properties of the 5 instances via its accessors.
Project_B contains Class B.
P_B asks P_A to get the 5 instances of C_A.
P_B gets the properties of the 5 instances.
Project_D contains Class D.
P_D does set and get the properties via the accessors of C_B and C_C.
Project_E contains Class E.
Project_E works on a different property of A.

P_B knows P_A
P_C knows P_A
P_D knows P_A, P_B, P_C
P_E knows P_A

These Projects are worked on by different parties.

Maybe this helps. Maybe it doesn't. Lets see.

Edit 2: Here another pseudo code example. Maybe this way it does make more sense to you. The key may be, that A does not know which properties it holds. (or more precisely, what they mean)

class A {
    map<int, int> props;
}

class B : private A {
    getProp1() { return props(1)}
    setProp1(int prop) { props(1) = prop }
}

class C : private A {
    getProp2() { return props(2)}
    setProp2(int prop) { props(2) = prop }
}

class D : public B, public C {
  // This is just a combination of B and C for comfort.
}

class E : private A {
    getProp3() { return props(3)}
    setProp3(int prop) { props(3) = prop }
}
xeed
  • 925
  • 8
  • 22
  • 2
    Although `(B*)a` works for you, it is undefined behavior. – aschepler Feb 25 '16 at 13:48
  • 1
    How do you expect casting an `A` tyo a `D` would work? An `A` is not a `D`. – NathanOliver Feb 25 '16 at 13:51
  • You are totally right, in general this is not possible. But since D (and B,C) only contain methods it should be possible. I'm really asking for the right pattern here. – xeed Feb 25 '16 at 13:59
  • @xeed maybe you can because their is only methods, but I think - and it's only my opinion - that is something dangerous. Also, you miss virtual in your inheritance to have diamond inheritance. And if you have virtual somewhere (in inheritance or method) you don't have only method, you also have a vtable and so a pointer to a vtable! – Garf365 Feb 25 '16 at 15:07
  • Well, I do agree with your opinion. My goal is to achieve a losely coupled structure of independent accessors to a common class. As I've said there are easy static or procedural ways to achieve this. But I will have to do a lot with these classes, so I was looking for a decent object oriented way, which does provide easy access. – xeed Feb 25 '16 at 16:51

2 Answers2

1

B and C have to virtual inherit from A

class A {
public:
  A() { prop = 1; }
  int prop;
};

class B : virtual public A {
public:
  int getProp() { return prop; }
private:
  B();
};

class C : virtual public A {
public:
  int setProp(int v) { prop = v; }
private:
  C();
};

class D : public B, public C {
private:
  D();
};

usage() {
  A* a = new D(); //!!!! NEW D here
  B* b = dynamic_cast<B*>(a); // 
  b->getProp(); // 
  D* d = dynamic_cast<D*>(a); // Not diamond inheritance in cause, bad init of a!
  d->setProp(5);// 
  d->getProp();//
}

Also, use C++ cast (dynamic_cast, static_cast, ...). If you use it, it would be return a nullptr when you try casting A* a=new A() to B you should test result of dynamic_cast. With reference, dynamic_cast throw an exception. An A instance can be a B instance. But a D or a B, or a C instance can be a A instance. And D can also be a C or D instance.

Garf365
  • 3,619
  • 5
  • 29
  • 41
  • okay add a class E, which inherites from A, but has nothing to do with B,C,D and contains only methods aswell. That is why I'm creating an A and not a D, because A does not have to be a D. E wants to use the properties of A aswell. I hope this clarifies the thing I'm trying to do. – xeed Feb 25 '16 at 14:03
  • 1
    `dynamic_cast` doesn't throw when you cast pointers, it returns a null pointer if the cast fails. Casting references throws `std::bad_cast` when it fails. – Emil Laine Feb 25 '16 at 14:28
0

So, obviously nobody seems to care anymore. So here is the solution I wanted to circumvent.

class A {
public:
  map<string, string> keyvalue;
}
class B {
  static string getProp1(A* a) { return a->keyvalue.find("prop_1")->second;}
}

class C {
  static string getProp2(A* a) { return a->keyvalue.find("prop_2")->second;}
}

class BandC : public B, public C {
  //THis is just a combination of B and C
}

Since classes B and C only contain functions, there would have been logically no need for a real instance of them. They can basically operate on an instance of class A.

In case it is not clear. If I inherit B and C from A and combine them again in BandC, I get the error because of the diamond shape.

xeed
  • 925
  • 8
  • 22