Multiple Inheritance

Pages: 12
I rewrote my code. PLEASE consider this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
struct Beatle {
	int Age;
};

struct ExperienceInSinging {
	int SingingYears;

	ExperienceInSinging() {SingingYears = 10;};
};

struct ExperienceInDrumming {
	int DrummingYears;

	ExperienceInDrumming() {DrummingYears = 15;};
};

struct ExperienceInGuitar {
	int GuitarYears;

	ExperienceInGuitar() {GuitarYears = 20;};
};

struct ExperienceInPiano {
	int PianoYears;

	ExperienceInPiano() {PianoYears = 25;};
};

struct Paul : public Beatle, ExperienceInSinging, ExperienceInGuitar {
};

struct John : public Beatle, ExperienceInSinging, ExperienceInGuitar, ExperienceInPiano {
};

struct George : public Beatle, ExperienceInSinging, ExperienceInPiano {
};

struct Ringo : public Beatle, ExperienceInDrumming {
};

struct BeatleContainer {
	Beatle * b;

	int getSingingExperience() {
		return ((ExperienceInSinging *) b)->SingingYears;
	};

	int getDrummingExperience() {
		return ((ExperienceInDrumming *) b)->DrummingYears;
	};

	int getGuitarExperience() {
		return ((ExperienceInGuitar *) b)->GuitarYears;
	};

	int getPianoExperience() {
		return ((ExperienceInPiano *) b)->PianoYears;
	};

	void createMember(int member) {
		switch (member) {
			case 1:
				b = new Paul;
				break;
			case 2:
				b = new John;
				break;
			case 3:
				b = new George;
				break;
			case 4:
				b = new Ringo;
				break;
		};
	};
};

int main() {
	BeatleContainer bc;
	bc.createMember(2);
	int i = bc.getSingingExperience();
	return 0;
};


Why does i not contain 10????
Last edited on
I don't think the compiler know how to cast from RS_A* to RS_B* because the types doesn't have anything in common. If you had used C++ styled cast (static_cast) it would have given you an error.

A RS_AB object contains both a RS_A part and a RS_B part. The RS_A part is probably stored first and the RS_B part is stored after the RS_A part.
1
2
3
4
|    RS_A    |     RS_B     |
-----------------------------
^
RS_AB*

To convert from RS_AB* to RS_A* it doesn't have to do anything with the pointer because the pointer already points to the RS_A part.
1
2
3
4
|    RS_A    |     RS_B     |
-----------------------------
^
RS_A*

When converting from RS_AB* to RS_B* it has to add an offset (sizeof(RS_A) + padding) to make it point to the RS_B part.
1
2
3
4
|    RS_A    |     RS_B     |
-----------------------------
             ^
             RS_B*


The types RS_A and RS_B has nothing to do with each so you can't convert RS_A* to RS_B* implicitly or by using static_cast. What you can do is using reinterpret_cast but that will not care about offsets or anything so you end up with a RS_B* pointer pointing to the RS_A part.
1
2
3
4
|    RS_A    |     RS_B     |
-----------------------------
^
RS_B*

That is obviously not what you want.
Last edited on
Thanks for this. That's a really good explanation!

Time for a restructure
Last edited on
Thanks for posting your code. The situation is much clearer now. How about thinking of it like this.

You have class Band. This is made up of Members. Each member has spent some time on some skill. The Band's total experience for a given skill is the sum of that skill for each Member.

One object design perspective is, you have objects Band, Member and Skill.

A Band has a unordered collection of Members. Each Member has a unordered collection of Skills. Each Skill is a skill type and length of experience. We can just use an enumeration to represent the still type.

Now that we have some kind of design, we can build it.

An implementation that falls out of that model would be something like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Skill
{
    int years_experience;
public:
    enum EType { ESing, EDrum, EGuitar, EPiano };
    // ...
};

class Member
{
    std::set<Skill*> skills;
    // ...
};

class Band
{
    std::set<Member*> members;
    //...
};

int main()
{
    Member* george = new Member;
    george->addSkill(Skill::EDrum, 2);
    george->addSkill(Skill::ESing, 3);
    // repeat for each member

    Band* beatles = new Band;
    beatles->addMember(george);
    // and so on 


The point is, you have to start with a design and then implement it. C++ just has too may tools to just start coding as you'll always get lost without a design.
Last edited on
This mixin stuff is interesting.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

struct Beatle {
	int Age;
};

template<typename s>
struct ExperienceInSinging : public s {
	int SingingYears;

	ExperienceInSinging() {SingingYears = 10;};
};

template<typename s>
struct ExperienceInDrumming : public s {
	int DrummingYears;

	ExperienceInDrumming() {DrummingYears = 15;};
};

template<typename s>
struct ExperienceInGuitar : public s {
	int GuitarYears;

	ExperienceInGuitar() {GuitarYears = 20;};
};

template<typename s>
struct ExperienceInPiano : public s {
	int PianoYears;

	ExperienceInPiano() {PianoYears = 25;};
};

typedef ExperienceInSinging<ExperienceInGuitar<Beatle>> Paul;
typedef ExperienceInSinging<ExperienceInGuitar<ExperienceInPiano<Beatle>>> John;
typedef ExperienceInSinging<ExperienceInPiano<Beatle>> George;
typedef ExperienceInDrumming<Beatle> Ringo;
I am trying to code something that can be used on MCU and desktop.

If it is used on MCU then it needs to be the smallest size possible. I don't want to have extra variables taking up space. I don't want anything on the chip that isn't being used explicitly.

But at the same time, I want to have a single object (which would be benefit from above, or mixin, style functionality)... but could be passed around as a generic object... ie, the beatle struct.
...but as i have discovered... referring to the struct as a beatle struct will always lose its functionality regardless of being type casted with a struct used in its inheritance.
whats the overhead for templates.
You get a separate copy of code for each different type you use. So, in my example above, there will be two copies of the std::set code (for Skill* and Member*). It's called code bloat.

I think you are confusing a class and an instance of a class. The latter code is hard coding the configuration. Any corrections to what Paul does means changing the program and not the data, for example. It really ought to be data driven.
The problem I have is my code is bigger than this example. And from looking at this example, I would agree with what u said. But the ACTUAL project... cant be data driven.

i need to find a way of bringing together chucks of data/functionality in such a way that there is little (or really, no) overhead in doing so.

also, i want to have a single object that can be created and initialised in many forms.

for instance, my first thought was to strip out functionality using macros and #ifdef for each bit... not nice.

so i tried multiple inheritance but as was explained, as soon as i lose track of what the original classtype is, i lose access to where in memory i should be looking for members... because it can change.


i know i am not making much sense, but pls stick with me on this... there is reason behind this strange request :)
kbw wrote:
So, in my example above, there will be two copies of the std::set code (for Skill* and Member*).
A good compiler should be able to recognize that the functions are identical and reuse the same code for both.
i know i am not making much sense, but pls stick with me on this...
We'll try to answer any questions you have.

i need to find a way of bringing together chucks of data/functionality in such a way that there is little (or really, no) overhead in doing so.
I thought that the example I gave did that. You can add more bands and more members to each bands without changing the code, the whole thing could be constructed from a database for example. But that's not what you have in mind, can you elaborate on your thinking, perhaps with an example.
kbw. i appreciate you putting together that code... the problem is your code is perfect when u rewrite my example... but that is only an example of my code, not the final thing.

check this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

//*****//


class PositionBuffer {
public:
	int count;
	char positions;


	PositionBuffer() {count=2;};
};


class Boundaries {
public:
	char boundaryfrom;
};


class TransformList {
public:
	char transform;
};


//*****//


class PB {
public:
	PositionBuffer pb;
	Boundaries b;
};


class PT {
public:
	PositionBuffer pb;
	TransformList tl;
};


class PBT {
public:
	PositionBuffer pb;
	Boundaries b;
	TransformList tl;
};


//*****//


template <class S>
class container {
public:
	S * temp;


	container() {temp = new S;};
};


//*****//


template <class Base, class S>
class BOptions : public Base {
public:
	void setBoundaries() {
		((container<S> *) this)->temp->b.boundaryfrom = 123;
	};
};


template <class Base, class S>
class TOptions : public Base {
public:
	void setTransforms() {
		((container<S> *) this)->temp->tl.transform = 30;
	};
};


//*****//


typedef BOptions<container<PB>, PB> ContainerPB;


//*****//


void main() {
	ContainerPB c;
	c.setBoundaries();
	//c.setTransforms(); //error
	int i = c.temp->b.boundaryfrom;
};


I wrote this at work... its untested so dont point out any obvious bugs...

Its a conceptual idea that would meet my needs... but will it work?>? dunno til i gets home

Edit: Please don't just point out I could have done this same structure with traditional inheritance and a few classes... i realise that... its testing a theory of multiple inheritance/mixin/holding minimum data structures
Last edited on
Thanks for your post. I am not quite clear on what you want to do.

Can you please describe in words what you're doing. Hopefully I'll my head around the problem with the words, that example and what we've looked at so far.
PositionBuffer, Boundaries and TransformList are all classes that contain nothing but portions of data. PB, PT and PBT are possible combinations of these classes.

They require no virtual table (I hope) and no struct inheritance.

If I put these on an MCU they only require EXACTLY the amount of data I have specified. No unused variables or unused pointers to variables.

I will have a list of functions which deal with these data types directly. They will be held in a namespace away from the code. I will pass in the container with something like ns::whatever(container).

Now, part 2, i suppose.

I have a container containing a pointer to one of these objects. (Later there will be more stuff in it, for this example, one pointer will do). This object can be used on something with a bit more kick (bigger MCU) or on a PC.

In order to make this container object have access to all my functions... and have the ability to do container.whatever() rather than ns::whatever(container)... I have used mixin to add functionality.

Then, to make the object easier to create, i have a typedef with a friendly name (for each valid container object).

What dya think?


Edit: Well it works... even applied it to my actual code with complete success :) Still intrigued to know if there are any shortcomings with this technique I haven't come across yet?
Last edited on
What dya think?
I still don't understand as I don't know what PositionBuffer, Boundaries and TransformList really are or what an MCU is.

Whatever you're doing, I don't see generalisation (inheritance). And if you're dealing with fixed kinds of data, you probably don't need Object technology either.

As you have something working that you're comfortable with, all I can do is wish you well with this project.
Then I shall say thank you for all your help and bid you a good day, Sir.
Topic archived. No new replies allowed.
Pages: 12