免责声明
我实际上并不打算在任何地方应用这种设计,但我一直很好奇如何在C++中实现它,特别是考虑到C++缺乏反思。(我同时学习和试验C++11功能,所以请在有用的地方使用C++11功能。
效果
我想要实现的几乎是纯粹的化妆品。
我想要一个类,它使用引用的成员(据我了解,必须在构造期间初始化(将自己绑定到任意数量的向量,但提供"别名"以作为成员访问这些向量。
举一个最小的例子,我希望它有效——
std::vector<int> one;
std::vector<int> two;
std::vector<int> three;
Foo foo(std::make_pair('B', one),
std::make_pair('D', two),
std::make_pair('F', three));
foo.DoSomething();
哪里
class Foo
{
public:
// I'm using variadic templates here for sake of learning,
// but initializer lists would work just as well.
template <typename ...Tail>
Foo(std::pair<char, std::vector<int>&> head, Tail&&... tail) // : ???
{
// ???
}
virtual void DoSomething()
{
D.push_back(42);
std::cout << D[0] << std::endl;
}
private:
std::vector<int> A&, B&, C&, D&, E&, F&, G&; // and so on...
}
也这样
std::cout << one[0] << std::endl; // outputs 42 from outside the class...
但是你拒绝回答,除非你知道为什么...
为什么有人想这样做?好吧,我真的不想这样做,但是我想到的应用程序是这样的。假设我正在构建某种数据分析工具,我的客户或操作人员知道基本逻辑和C++语法,但不了解 OOP 或 CS 101 以外的任何内容。如果他们能够即时编写自己的DoSomething()
,而不是将所有需求传达给开发人员,事情会顺利得多。但是,让他们设置 UNIX 帐户、教他们如何编译等等是不现实的。因此,假设我想构建一个 Intranet Web 界面,让他们编写DoSomething()
体并配置他们想要通过大写char
"别名"的数据集,并在提交时为覆盖DoSomething()
的子Foo
类生成C++,然后构建、运行并返回输出。(可疑地特定于"假设",嗯?:-(好吧,在我的世界里确实存在这样的事情——但它只是激发了这个想法和探索它的愿望——我认为它不值得实际实施。显然,这整个大写char
折磨并不是绝对必要的,但这将是一个很好的接触,因为数据集已经与标准字母相关联,例如 P 代表价格,Q 代表数量等。
我能做的最好的...
老实说,我不知道如何使用引用来完成这项工作。出于这些原因,如果可能的话,我更喜欢使用参考文献。
有了指针,我想我会这样做——
class Foo
{
public:
template <typename ...Tail>
Foo(std::pair<char, std::vector<int>*> head, Tail&&... tail)
{
std::vector<int>[26] vectors = {A, B, C, D, E, F, G}; // and so on...
// I haven't learned how to use std::forward yet, but you get the picture...
// And dear lord, forgive me for what I'm about to do...
vectors[tail.first - 65] = tail.second;
}
virtual void DoSomething()
{
D->push_back(42);
std::cout << (*D)[0] << std::endl;
}
private:
std::vector<int> A*, B*, C*, D*, E*, F*, G*; // and so on...
}
但即使这样也不是那么优雅。
有没有办法使用引用并实现这一点?
有没有办法使其更通用,例如使用伪反射方法来避免再次列出所有大写字母?
关于以更优雅或紧凑的方式保留主要目标(我描述的外观别名(的替代设计的任何建议?
你可以使用这样的东西:
class Foo
{
public:
template <typename ...Ts>
Foo(Ts&&... ts) : m({std::forward<Ts>(ts)...}),
A(m.at('A')),
B(m.at('B'))
// and so on...
{
}
virtual void DoSomething()
{
A.push_back(42);
std::cout << A[0] << std::endl;
}
private:
std::map<char, std::vector<int>&> m;
std::vector<int> &A, &B; //, &C, &D, &E, &F, &G; // and so on...
};
但这需要给出每个向量,所以
Foo(std::vector<int> (&v)[26]) : A(v[0]), B(v[1]) // and so on...
{
}
或
Foo(std::vector<int> &a, std::vector<int> &b /* And so on */) : A(a), B(b) // and so on...
{
}
似乎更合适。
活生生的例子。
如果是拥有vector
的类Foo
,似乎更简单,所以你只会有
class Foo
{
public:
virtual ~Foo() {}
virtual void DoSomething() { /* Your code */ }
std::vector<int>& getA() { return A; }
private:
std::vector<int> A, B, C, D; // And so on
};
并提供 getter 来初始化内部向量。
然后
std::vector<int>& one = foo.GetA(); // or foo.A if you let the members public.