繁体   English   中英

在c ++中使用私有拷贝构造函数有什么用处

[英]What's the use of the private copy constructor in c++

为什么人们定义私有拷贝构造函数?

何时使复制构造函数和赋值运算符私有化是一个好的设计?

如果类中没有成员是唯一对象(如文件名)的指针或句柄,那么在其他情况下,私有拷贝构造函数是个好主意吗?

同样的问题适用于赋值运算符。 鉴于大多数C ++围绕复制对象并通过引用传递,是否有任何涉及私有拷贝构造函数的好设计?

一个用例是单例模式 ,其中只能有一个类的实例 在这种情况下,您需要使构造函数和赋值operator = private,以便无法创建多个对象。 创建对象的唯一方法是通过GetInstance()函数,如下所示。

// An example of singleton pattern
class CMySingleton
{
public:
  static CMySingleton& GetInstance()
  {
    static CMySingleton singleton;
    return singleton;
  }

// Other non-static member functions
private:
  CMySingleton() {}                                  // Private constructor
  ~CMySingleton() {}
  CMySingleton(const CMySingleton&);                 // Prevent copy-construction
  CMySingleton& operator=(const CMySingleton&);      // Prevent assignment
};

int main(int argc, char* argv[])
{
  // create a single instance of the class
  CMySingleton &object = CMySingleton::GetInstance();

  // compile fail due to private constructor
  CMySingleton object1;
  // compile fail due to private copy constructor
  CMySingleton object2(object);
  // compile fail due to private assignment operator
  object1 = object;

  // ..
  return 0;
}

某些对象表示不能或不应复制的特定实体。 例如,您可以阻止复制表示应用程序使用的日志文件的对象,这与期望代码的所有部分将使用单个日志文件相对应。 使用意外或不正确复制的对象可能导致日志中出现无序内容,当前日志大小的不准确记录,多次尝试(某些失败)“滚动”到新的日志文件名或重命名现有文件名。

另一个用途是通过虚函数强制执行复制。 由于构造函数不能是virtual ,因此通常的做法是阻止直接访问复制构造函数并提供virtual Base* clone()方法,该方法返回指针指向的实际运行时类型的副本。 这可以防止Base b(derived)出现的意外切片。

另一个例子:一个死简单的智能指针对象,它简单地删除它在构造函数中给出的指针:如果它不支持引用计数或其他一些处理多个所有者的方式,并且不希望有风险笨拙的意外std::auto_ptr样式的所有权转移,然后简单地隐藏复制构造函数给出了一个很棒的小智能指针,它对于可用的有限情况快速有效。 关于尝试复制它的编译时错误会有效地要求程序员“嘿 - 如果你真的想这样做会把我改成共享指针,否则就会退回!”。

一个非常糟糕的例子:

class Vehicle : { int wheels; Vehicle(int w) : wheels(w) {} }

class Car : public Vehicle { Engine * engine; public Car(Engine * e) : Vehicle(4), engine(e) }

...

Car c(new Engine());

Car c2(c); // Now both cars share the same engine!

Vehicle v;
v = c; // This doesn't even make any sense; all you have is a Vehicle with 4 wheels but no engine.

“复制”汽车意味着什么? (汽车是汽车模型,还是汽车的实例?复制它是否可以保留车辆登记?)

将车辆分配给另一辆车是什么意思?

如果操作没有意义(或仅仅是未实现),那么标准的做法是使复制构造函数和赋值运算符保持私有,如果使用它们而不是奇怪的行为,则会导致编译错误。

将复制构造函数和复制赋值设置为私有的常见原因是禁用这些操作的默认实现。 但是,在C ++ 0x中,为此目的有特殊的syntax = delete 因此,在C ++ 0x中,复制ctor private似乎被重新定义为非常奇特的情况。

复制ctors和作业是相当的语法糖; 所以这种“私人糖”似乎是贪婪的症状:)

即使对象的内容不是指针或其他引用,阻止人们复制对象仍然是有用的。 也许该类包含大量数据,并且复制过于重量级的操作。

您可能希望使用复制构造函数实现该类的某些方法,但不要将其暴露在类之外。 那么你把它变成私有的。 像任何其他方法一样。

虚拟构造函数习惯用法 ”是一个需要私有或受保护的拷贝构造函数的重要案例。 在C ++中出现了一个问题,在这个问题中,您将获得指向基类的指针,该对象实际上是从该基类继承的,并且您想要复制它。 调用复制构造函数不会调用继承类的复制构造函数,而是实际调用基类的复制构造函数。

注意:

class Base {

public:
   Base( const Base & ref ){ std::cout << "Base copy constructor" ; }
};

class Derived : public Base {

public:
   Derived( const Derived & ref ) : Base(ref) { std::cout << "Derived copy constructor"; }
}

Base * obj = new Derived;
Base * obj2 = new Derived(*obj);

上面的代码会产生输出:

"Base copy constructor"

这显然不是程序员想要的行为! 程序员试图复制“Derived”类型的对象,而是返回“Base”类型的对象!

通过使用上述习语来纠正该问题。 观察上面写的例子,重写使用这个成语:

class Base {

public:
  virtual Base * clone () const = 0; //this will need to be implemented by derived class

protected:
   Base( const Base & ref ){ std::cout << "Base copy constructor" ; }
};

class Derived : public Base {

public:
  virtual Base * clone () const {

    //call private copy constructor of class "Derived"
    return static_cast<Base *>( new Derived(*this) );
  }

//private copy constructor:
private:
   Derived( const Derived & ref ) : Base(ref) { std::cout << "Derived copy constructor"; }
}

Base * obj = new Derived;
Base * obj2 = obj->clone();

上面的代码会产生输出:

"Base copy constructor"
"Derived copy constructor"

换句话说,用所需类型“Derived”构造的对象,而不是“Base”类型!

正如您所看到的,在Derived类型中,复制构造函数是故意设置为私有的,因为让程序员无意中尝试手动调用复制构造函数而不是使用clone提供的聪明接口是不好的API设计( )。 换句话说,可直接调用的公共拷贝构造函数可能会导致程序员犯下第1部分中提到的错误。在这种情况下,最佳实践是隐藏复制构造函数,并且只能通过使用“clone”方法间接访问)”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM