我正在尝试确定哪些模式可用于以更“组合”和更少“命令”的方式声明C ++类。
我正在尝试写一个包含多个MyDescriptor
成员的类。 MyDescriptor
需要由MyHost
类构造函数初始化,并且迭代对MyHost
成员的引用来执行此操作。
有没有办法声明MyHost
实现不需要单独向容器添加类成员引用?
class MyDescriptor {
public:
string name;
string fqn;
MyHost(string n) : name(n) {}
void init(string host) {
fqn = host + ":" + name;
}
void do_thing() {
// subclasses to special things.
}
}
class MyHost {
public:
vector<MyDescriptor*> descriptors;
string name
MyHost(string n, vector<MyDescriptor*> d) : name(n),descriptors(d) {
for (MyDescriptor *d : descriptors) {
d->init(name);
}
}
}
MyHostImpl : public MyHost {
public:
// descriptors must be accessible as members like this
MyDescriptor d_1 = MyDescriptor("abc");
MyDescriptor d_2 = MyDescriptor("123");
MyHostImpl(string n) : MyHost(n, {&d_1, &d_2}) {} // This is the issue
void do_thing_1() {
// UPDATE: This is loose example - but what is important to
// know is that developers need to access / use descriptors
// in methods like this.
d_1.do_thing();
}
}
我理想地想要一种方法来停止明确地声明descriptors
项目;这个{&d_1, &d_2}
是我想要消除的。我的团队使用了类似的模式,并且在将其添加到类后不小心不向向量添加描述符时经常感到沮丧。
反转ctor语义。取代主机ctor接受描述符指针,让描述符的ctor接受主机引用并将其自身添加到主机向量:
MyDescriptor::MyDescriptor(MyDescriptor const&)=delete;
auto& MyDescriptor::operator=(MyDescriptor const&)=delete;
MyDescriptor::MyDescriptor(string n, MyHost& h): name{n},fqn{n+":"+h.get_name()}
{
h.add(this);
};
MyHost::MyHost(string n):name{n}{};
void MyHost::add(MyDescriptor* d){
descriptors.push_back(d);
};
auto& MyHost::get_name()const{
return name;
};
这样你就不会忘记将描述符添加到主机或编译器的哭声中。
MyHostImpl::MyHostImpl(string n):
MyHost{n},
d_1{"abc",*this},/*compiler kills you if you forget this line*/
d_2{"123",*this}/*compiler kills you if you forget this line*/
{};
是的,至少在C ++ 14中有一种直接做你所要求的方法,但它涉及一堆黑暗伏都教。在本次C ++ 2018会议中的讨论:
Better C++14 reflections - Antony Polukhin
Antony解释了如何能够遍历结构的所有成员并访问其类型。他使用它来打印某些输出流上的值,但您可以使用相同的方法将地址推回到std::vector<MyDescriptor*>
。
话虽如此 - 我认为你应该避免这种模式。只需创建一个MyDescriptors矢量,然后使用它的引用。为什么要使用需要如此多扭曲才能生成的指针向量?
我不确定你会怎么想这会起作用。 C ++没有反射,所以你无法迭代它的类成员并检查它们的类型。所以,对不起,我不知道所有可能。您当然可以使用一些变通方法,例如直接简单地使用底层基本向量而不是将两个描述符声明为成员变量(您有什么理由需要吗?)然后在Base构造函数中隐式传递它们,但是您要做什么?重新瞄准是不可能的。
编辑:显然它可能有一些黑暗巫毒魔法,请参阅下面的评论。