C++ 防止复制成员数据

标签 c++

我有一个不寻常的情况,

假设我有一个如下所示的类,

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::vectoroperator[] 将返回一个引用,此类还必须通过返回引用为客户端提供完全访问权限。 setter/getter 对不行。

但是,与 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 属性。

要求 T 仅在大小相同时才允许复制或赋值也不是一个选项。因为,当复制 C 对象时,源和目标之间的大小可能不同。例如,

C c1(10);
C c2(20);
c1 = c2;

完全合理。 c1 的大小已更改,但其所有成员也更改为相同的新大小,因此没问题。

我希望我已经把问题说清楚了。我总结一下,我希望 CT 没有太多限制,T 基本上可以是具有所需构造函数的任何类型。 T 可以被复制和赋值。我唯一不希望客户端做的事情是通过 C::value() 分配给 value_

最佳答案

如果您希望用户能够调用对象上的非常量成员函数,并且希望返回对实际对象的引用,则不能完全禁止赋值,因为赋值运算符基本上就是 (您可以将 a = b 重写为 a.operator=(b) )。因此,您要么只需要返回对对象的 const 引用,要么将包含的对象设置为 non_copyable或者接受它可以被分配的事实。

我个人建议重新考虑设计。即使你可以禁止赋值,也不能保证该对象没有成员函数,这基本上与你的想法相同( .swap(...) 是一个典型的候选者),所以只要满足以下条件你就没有真正赢得任何东西您允许调用非常量成员函数。

但是,如果您只关心禁止意外分配,则可能会使进行此类分配变得更加困难。如果您T不是内置的,您可以创建一个派生类,它不会公开公共(public)赋值运算符并返回对此的引用:

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_;
 };

这将允许通过继承访问所有公共(public)成员,但隐藏赋值运算符(和构造函数)。当然,如果您使用 c++11,可以通过使用/定义移动构造函数/赋值并使用完美转发来增强此代码,以允许不同的构造函数。请注意,仍然可以使用 static_cast<T&>(C.value()) = foo 来分配 Derived 的 T 部分;

为了支持您无法派生的类型(内置函数...),您需要创建一个代理,该代理公开除赋值之外的所有功能。

关于C++ 防止复制成员数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13787786/

相关文章:

C++ 将值设置为类内的枚举项

c++ - undefined reference c++,异常情况

c++ - C 和 C++ .lib 文件是否可移植?

C++ 找不到运算符

c++ - 如何按类型启用 protected 方法

c++ - static const char * - 已定义但未使用

c++ - Linux、Eclipse、ARM 工具链和 Codan 错误

c++ - 在 V8 javascript 引擎中,如何为每个实例创建一个重用 ObjectTemplate 的构造函数?

c++ - 访问指针 vector 中的信息

c++ - 来自字符串元素的奇怪转换