[英]C++ Prevent copy a member data
我有一个不寻常的情况,
说我有一个像下面这样的课程,
template <typename T>
class C
{
public :
C (int size) : value_(size), some_other_member_(size) {}
T &value () {return value_;}
const T &value() const {return value_;}
private :
T value_;
SomeOtherType some_other_member_;
};
设计的类使客户端可以完全访问成员value_
,就像std::vector
的operator[]
将返回引用一样,该类还必须通过返回引用来赋予客户端完全访问权限。 设置器/获取器对将不起作用。
但是,与std::vector
不同,我不想允许客户端完全替换成员。 也就是说,客户端应能够调用value_
const
或非const
成员,但不允许以下行为,
C<SomeType> c(10);
SomeType another_value(5);
c.value() = another_value; // This shall not be allowed
有什么办法可以让客户完全访问value_
。 从某种意义上说,类C
就像一个容器,但是一旦它包含的东西被初始化(通过构造函数,对T
有一些要求,但这在这里不相关),客户端只能通过T
的成员来修改value_
函数,而不是通过赋值替换value_
。
但是,要求T
不可复制不是我的选择。 因为可以复制C
类。 问题的核心是,如在类C
所见, C
具有几个成员,它们都具有size
属性,在构造时,如果允许value_
通过赋值替换而被构造为相同的size
, ,则在成员可能不再具有相同的size
属性的意义上,它允许破坏数据结构。
要求T
仅在大小相同时才允许复制或分配也是一种选择。 因为在复制C
对象时,源和目标之间的大小可能会有所不同。 例如,
C c1(10);
C c2(20);
c1 = c2;
是完全合理的。 c1
的大小已更改,但是其所有成员也都更改为相同的新大小,因此可以。
我希望我已经阐明了这个问题。 我总结一下,我希望C
对T
不会造成太多限制, T
基本上可以是具有所需构造函数的任何类型。 可以复制和分配T
我不希望客户端执行的唯一操作是通过C::value()
分配给value_
。
如果您希望用户能够在对象上调用非const成员函数,并且希望返回对实际对象的引用,则不能完全禁止赋值,因为赋值运算符基本上就是这样(您可以重写a = b
作为a.operator=(b)
)。 因此,您只需要返回对您的对象的const引用,使包含的对象non_copyable
或者non_copyable
可以被分配给它的事实。
我个人建议重新考虑设计。 即使您可以禁止分配,实际上也无法保证该对象没有成员函数,该成员函数的想法基本相同( .swap(...)
是典型的候选对象),因此您并没有真正赢过只要您允许调用非const成员函数,就可以执行任何操作。
但是,如果仅考虑禁止意外分配,则可以使进行此类分配变得更加困难。 如果您的T
不是内置的,则可以创建一个派生类,该派生类不公开公共赋值运算符,并返回对此的引用:
template <typename T>
class C{
public :
class Derived: public T {
private:
Derived(int size):T(size) {}
Derived& operator=(const Derived&) = default; //used C++11 syntax for brevity, for C++03 code it has to be implemented here
Derived(const Derived&) = default; //don't want this class to be copyied outside of C
~Derived() = default;
friend class C;
};
C (int size) : value_(size), some_other_member_(size) {}
Derived& value () {return value_;}
const Derived& value() const {return value_;}
private :
Derived value_;
SomeOtherType some_other_member_;
};
这将通过继承访问所有公共成员,但隐藏赋值运算符(和构造函数)。 当然,如果您使用c ++ 11,则可以通过使用/定义移动构造函数/分配并使用完美的转发来增强此代码,以允许使用不同的构造函数。 注意,仍然可以使用static_cast<T&>(C.value()) = foo
来分配Derived的T部分。
为了支持您不能从(buildins ...)派生的类型,您需要创建一个代理,该代理公开除赋值外的所有功能。
关于您的吸气剂/吸水剂问题,我会写
const T& value() const; // as getter
void value(const T&); // as setter
返回const T&
(常量引用)恰好是针对c.value() = 10
(请参见例如Scott Meyers的Effective C ++,第23条)。
我认为这也解决了复制问题:您的课程仍然可以复制。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.