好的,我找到了一个可行的解决方案,并添加了 Thing 是抽象的信息(从而使解决方案变得更加困难并且上述解决方案无效):
#include <iostream>
#include <string>
struct Thing {
struct PartialData { int width, length, height, mass; }; //**Added
struct PartialDataTag {}; //**Added
std::string name;
int width, length, height, mass;
Thing() = default;
Thing (const std::string& n) : name(n) {}
Thing (const std::string& n, int w, int l, int h, int m) :
name(n), width(w), length(l), height(h), mass(m) {}
Thing (const std::string& n, const PartialData& data) : // ***Added
name(n), width(data.width), length(data.length), height(data.height), mass(data.mass) {}
void print() const {std::cout << name << ", " << width << ", " << length << ", " << height << ", " << mass << '\n';}
protected:
void setUsingPartialData (const PartialData& data) { // ***Added
width = data.width; length = data.length; height = data.height; mass = data.mass;
}
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(PartialDataTag{}) {} // ***Changed
};
struct Blob : virtual Thing {
static const PartialData partialData;
Blob (const std::string& name) : Thing (name, partialData) {}
Blob (PartialDataTag) {setUsingPartialData(partialData);} // ***Added
virtual void foo() override {}
};
const Thing::PartialData Blob::partialData = {3, 4, 5, 20}; // ***Added
int main() {
Blob blob("Blob");
ClonedType<Blob> b("New Blob", blob);
blob.print(); // Blob, 3, 4, 5, 20
b.print(); // New Blob, 3, 4, 5, 20
}
谁能想到更好的解决方案?许多新添加的东西使它工作,但至少信息3, 4, 5, 20在这里只被使用一次。
不过,我马上就能想到这个解决方案的一个严重缺陷。假设另一个派生自Thing 的具体类使用不同类型的部分数据(比如{int, int} 仅用于width 和mass),那么我上面的解决方案不适用于这个新类,对吧?
添加到问题中:
struct Sample : virtual Thing {
Sample (const std::string& name, int length, int height) :
Thing(name, 10, length, height, 50) {}
virtual void foo() override {}
};
如何实例化
ClonedType<Sample>
并正确初始化它?所有Sample 对象的宽度应为10,质量为50。哦,让我们进一步假设Thing 具有更多std::string 数据成员(对于Sample 也是静态值),因此我们不能求助于使用模板(例如 Sample : Data) 来定义Sample 类。
更新:已解决!
#include <iostream>
#include <string>
struct Thing {
struct PartialData { std::string codeName; int width, length, height, mass; };
struct PartialDataTag {};
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
}