我正在尝试为我的软件定义一个好的设计,这意味着要小心对某些变量的读/写访问。在这里,我简化了讨论的程序。希望这对其他人也有帮助。:-)
假设我们有一个 X 类,如下所示:
class X {
int x;
public:
X(int y) : x(y) { }
void print() const { std::cout << "X::" << x << std::endl; }
void foo() { ++x; }
};
还可以说,将来这个类将被 X1、X2、... 子类化,这可以重新实现print()
和foo()
. (为了简单起见,我在这里省略了必需的virtual
关键字,因为这不是我面临的实际问题。)
由于我们将使用多态,让我们使用(智能)指针并定义一个简单的工厂:
using XPtr = std::shared_ptr<X>;
using ConstXPtr = std::shared_ptr<X const>;
XPtr createX(int x) { return std::make_shared<X>(x); }
到现在为止,一切都很好:我可以定义goo(p)
哪些可以读写p
,hoo(p)
哪些只能读取p
。
void goo(XPtr p) {
p->print();
p->foo();
p->print();
}
void hoo(ConstXPtr p) {
p->print();
// p->foo(); // ERROR :-)
}
呼叫站点如下所示:
XPtr p = createX(42);
goo(p);
hoo(p);
指向 X( XPtr
) 的共享指针会自动转换为其 const 版本 ( ConstXPtr
)。不错,正是我想要的!
现在麻烦来了:我需要一个异构的X
. 我的选择是一个std::vector<XPtr>
。(也可以是list
,为什么不呢。)
我想到的设计如下。我有两个版本的容器:一种对其元素具有读/写访问权限,另一种对其元素具有只读访问权限。
using XsPtr = std::vector<XPtr>;
using ConstXsPtr = std::vector<ConstXPtr>;
我有一个处理这些数据的类:
class E {
XsPtr xs;
public:
E() {
for (auto i : { 2, 3, 5, 7, 11, 13 }) {
xs.emplace_back(createX(std::move(i)));
}
}
void loo() {
std::cout << "\n\nloo()" << std::endl;
ioo(toConst(xs));
joo(xs);
ioo(toConst(xs));
}
void moo() const {
std::cout << "\n\nmoo()" << std::endl;
ioo(toConst(xs));
joo(xs); // Should not be allowed
ioo(toConst(xs));
}
};
和ioo()
函数joo()
如下:
void ioo(ConstXsPtr xs) {
for (auto p : xs) {
p->print();
// p->foo(); // ERROR :-)
}
}
void joo(XsPtr xs) {
for (auto p: xs) {
p->foo();
}
}
如您所见,在E::loo()
和E::moo()
我必须做一些转换toConst()
:
ConstXsPtr toConst(XsPtr xs) {
ConstXsPtr cxs(xs.size());
std::copy(std::begin(xs), std::end(xs), std::begin(cxs));
return cxs;
}
但这意味着一遍又一遍地复制所有内容.... :-/
另外, inmoo()
是 const,我可以调用joo()
which 将修改xs
的数据。不是我想要的。在这里,我更喜欢编译错误。
完整代码可在ideone.com 获得。
问题是:是否可以做同样的事情但不将向量复制到它的 const 版本?或者,更一般地说,是否有一种既有效又易于理解的良好技术/模式?
谢谢你。:-)