C++:复制构造函数:直接使用getter或访问成员变量?

cbr*_*lak 2 c++ copy-constructor member-variables

我有一个带有复制构造函数的简单容器类.

您是否建议使用getter和setter,或直接访问成员变量?

public Container 
{
   public:
   Container() {}

   Container(const Container& cont)          //option 1
   { 
       SetMyString(cont.GetMyString());
   }

   //OR

   Container(const Container& cont)          //option 2
   {
      m_str1 = cont.m_str1;
   }

   public string GetMyString() { return m_str1;}       

   public void SetMyString(string str) { m_str1 = str;}

   private:

   string m_str1;
}
Run Code Online (Sandbox Code Playgroud)
  • 在示例中,所有代码都是内联的,但在我们的实际代码中没有内联代码.

更新(09年9月29日):

其中一些答案写得很好但是他们似乎忽略了这个问题的重点:

  • 这是一个简单的人为例子,讨论使用getter/setter和变量

  • 初始化列表或私有验证器函数实际上不是这个问题的一部分.我想知道这两种设计是否会使代码更容易维护和扩展.

  • 一些ppl在这个例子中专注于字符串,但它只是一个例子,想象它是一个不同的对象.

  • 我不关心表现.我们不是在PDP-11上编程

Ara*_*raK 11

编辑:回答编辑的问题:)

这是一个简单的人为例子, 讨论使用getter/setter和 变量

如果您有一个简单的变量集合,不需要任何类型的验证,也不需要额外的处理,那么您可以考虑使用POD.来自Stroustrup的FAQ:

精心设计的类为其用户提供了一个干净简单的界面, 隐藏其表示并使用户不必了解该表示.如果不应该隐藏表示 - 比如,因为用户应该能够以他们喜欢的方式更改任何数据成员 - 您可以将该类视为"只是一个普通的旧数据结构"

简而言之,这不是JAVA.你不应该写普通的getter/setter,因为它们和它们自己暴露变量一样糟糕.

初始化列表或私有验证器函数实际上不是这个问题的一部分.我想知道这两种设计是否会使代码更容易维护和扩展.

如果要复制另一个对象的变量,则源对象应处于有效状态.这个生病的源对象是如何在第一时间构建的?!构造函数不应该做验证工作吗?是不是修改成员函数负责通过验证输入来维护类不变量?为什么要在复制构造函数中验证"有效"对象?

我不关心表现.我们不是在PDP-11上编程

这是最优雅的风格,但在C++中,最优雅的代码通常具有最佳的性能特征.


你应该使用一个initializer list.在您的代码中,m_str1默认构造然后分配一个新值.你的代码可能是这样的:

class Container 
{
public:
   Container() {}

   Container(const Container& cont) : m_str1(cont.m_str1)
   { }

   string GetMyString() { return m_str1;}       
   void SetMyString(string str) { m_str1 = str;}
private:
   string m_str1;
};
Run Code Online (Sandbox Code Playgroud)

@cbrulak你不应该IMO验证cont.m_str1copy constructor.我所做的就是验证内容constructors.验证copy constructor意味着您首先复制一个不良格式的对象,例如:

Container(const string& str) : m_str1(str)
{
    if(!valid(m_str1)) // valid() is a function to check your input
    {
        // throw an exception!
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 复制对象时,源对象应该是有效对象. (2认同)
  • 对类的操作通常应该是导致复合事件的操作,否则您的类将转变为数据存储区缓存.您的日志记录示例 - 我希望将"复制"以不同方式记录到"设置"个人,当然不希望看到N个日志行的副本导致N值的设置. (2认同)

dcw*_*dcw 8

您应该使用初始化列表,然后问题变得毫无意义,如:

Container(const Container& rhs)
  : m_str1(rhs.m_str1)
{}
Run Code Online (Sandbox Code Playgroud)

Matthew Wilson的Imperfect C++中有一个很棒的部分解释了所有关于成员初始化列表的内容,以及如何将它们与const和/或引用结合使用以使代码更安全.

编辑:显示验证和const的示例:

class Container
{
public:
  Container(const string& str)
    : m_str1(validate_string(str))
  {}
private:
  static const string& validate_string(const string& str)
  {
    if(str.empty())
    {
      throw runtime_error("invalid argument");
    }
    return str;
  }
private:
  const string m_str1;
};
Run Code Online (Sandbox Code Playgroud)