Issues with virtual inheritance and static data

Consider the code below:

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
#include <iostream>
#include <string>

struct Thing {
	std::string name, codeName;
	int width, length, height, mass;
	
	Thing() = default;
	Thing (const std::string& n) : name(n) {}
	Thing (const std::string& n, const std::string& c, int w, int l, int h, int m) :
		name(n), codeName(c), width(w), length(l), height(h), mass(m) {}
	void print() const {std::cout << name << ", " << codeName << ", " << width << ", " << length << ", " << height << ", " << mass << '\n';}
	virtual void foo() = 0;  // Abstract class
};

struct Clone : virtual Thing {
	Thing& parent;
	Clone (const std::string& name, Thing& p) : Thing(name), parent(p) {}
};

template <typename T>
struct ClonedType : public Clone, public T {
	ClonedType (const std::string& name, Thing& t) : Thing(name), Clone(name, t), T(name) {}
};

// virtual inheritance needed because of ClonedType<Blob> being instantiated:
struct Blob : virtual Thing {
    Blob (const std::string& name) : Thing(name, "Bob", 3, 4, 5, 20) {}
    virtual void foo() override {}
};

struct Sample : virtual Thing {
	Sample (const std::string& name, int length, int height) : Thing(name, "Sam", 10, length, height, 50) {}
	virtual void foo() override {}
};

int main() {
	Blob blob("Blob");
	ClonedType<Blob> b("New Blob", blob);
	blob.print();  // Blob, Bob, 3, 4, 5, 20
	b.print();  // New Blob, , -1, -1, 4237013, 0  // Here's the problem!
}


Blob's constructor calls up Thing's constructor fine because of virtual inheritance, but because of that virtual inheritance ClonedType<T> fails to call up Thing's constructor through use of T's constructor.
As a result, b, which is of type Blob, is not properly initialized (all Blob objects are to share the same values 3, 4, 5, 20, and other values like strings and special types that I'm not showing here).
So how to fix this problem other than manually setting each of these values in the Blob constructor body (which would defeat the purpose of Thing(name, "bob", 3, 4, 5, 20))? Note that Thing is an abstract class.
Last edited on
Solved!

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
#include <iostream>
#include <string>

struct Thing {
	struct PartialData { std::string codeName;  int width, length, height, mass; };  // ***Added
	struct PartialDataTag {};  // ***Added
	std::string name, codeName;
	int width, length, height, mass;
	
	Thing() = default;
	Thing (const std::string& n) : name(n) {}
	Thing (const std::string& n, int l, int h) : name(n), length(l), height(h) {}
	Thing (const std::string& n, const std::string& c, int w, int l, int h, int m) :
		name(n), codeName(c), width(w), length(l), height(h), mass(m) {}
	Thing (const std::string& n, const PartialData& data) :
		name(n), codeName(data.codeName), width(data.width), length(data.length), height(data.height), mass(data.mass) {}
	void print() const {std::cout << name << ", " << codeName << ", " << width << ", " << length << ", " << height << ", " << mass << '\n';}
protected:
	void setUsingPartialData (const PartialData& data) {
		codeName = data.codeName;  width = data.width;  length = data.length;  height = data.height;  mass = data.mass;
	}
	virtual void foo() = 0;
};

struct Clone : virtual Thing {
	Thing& parent;
	template <typename... Args>
	Clone (Thing& p, Args&&... args) : Thing (std::forward<Args>(args)...), parent(p) {}
};

template <typename T>
struct ClonedType : public Clone, public T {
	template <typename... Args>
	ClonedType (Thing& t, Args&&... args) : Thing (std::forward<Args>(args)...), Clone(t, std::forward<Args>(args)...), T(PartialDataTag{}) {}
};

struct Blob : virtual Thing {
	static const PartialData partialData;
	Blob (const std::string& name) : Thing (name, partialData) {}
	Blob (PartialDataTag) {setUsingPartialData(partialData);}
	virtual void foo() override {}
};
const Thing::PartialData Blob::partialData = {"Bob", 3, 4, 5, 20};  // !

struct Sample : virtual Thing {
	static const int staticWidth = 10, staticMass = 50;
	Sample (const std::string& name, int length, int height) : Thing(name, "Sam", staticWidth, length, height, staticMass) {}
	Sample (PartialDataTag) {setUsingPartialData(getPartialData());}
	virtual void foo() override {}
	PartialData getPartialData() const {return {"Sam", staticWidth, length, height, staticMass};}  // !
};

int main() {
	Blob blob("Blob");
	ClonedType<Blob> b(blob, "New Blob");
	blob.print();  // Blob, Bob, 3, 4, 5, 20
	b.print();  // New Blob, Bob, 3, 4, 5, 20

	Sample sample("Sample", 11, 12);
	ClonedType<Sample> s(sample, "New Sample", 21, 22);
	sample.print();  // Sample, Sam, 10, 11, 12, 50
	s.print();  // Sample, Sam, 10, 21, 22, 50
}

But I'll leave this thread here in case someone can think of an easier solution.
Last edited on
Topic archived. No new replies allowed.