人们为什么要定义私有复制构造函数?
在什么情况下将复制构造函数和赋值运算符设为私有是一种良好的设计?
如果类中没有指向唯一对象(如文件名)的指针或句柄成员,那么除此之外,什么情况下使用私有复制构造函数是个好主意?
对于赋值运算符也适用同样的问题。鉴于大多数C ++围绕着对象的复制和引用传递,是否存在涉及私有复制构造函数的良好设计?
人们为什么要定义私有复制构造函数?
在什么情况下将复制构造函数和赋值运算符设为私有是一种良好的设计?
如果类中没有指向唯一对象(如文件名)的指针或句柄成员,那么除此之外,什么情况下使用私有复制构造函数是个好主意?
对于赋值运算符也适用同样的问题。鉴于大多数C ++围绕着对象的复制和引用传递,是否存在涉及私有复制构造函数的良好设计?
一个使用场景是单例模式,其中一个类只能有一个实例。在这种情况下,您需要将构造函数和赋值运算符=私有化,以确保没有创建多个对象的可能性。创建对象的唯一方法是通过下面显示的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;
}
=delete
版本(公共),以获得相同的结果吗? - FCo有些对象代表特定实体,这些实体不能或不应该被复制。例如,您可以防止复制表示应用程序使用的日志文件的对象,相应地期望所有代码部分都使用单个日志文件。意外或不当复制对象的使用可能导致日志中出现无序内容,记录当前日志大小不准确,多次尝试(有些失败)“滚动”到新的日志文件名或重命名现有文件。
另一个用途是通过虚函数强制复制。由于构造函数不能是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中有专门的语法=delete来实现这种目的。 因此,在C++ 0x中,将复制构造函数设为私有似乎只适用于非常特殊的情况。
复制构造函数和赋值运算符只是一些语法糖; 因此,这种“私有语法糖”似乎是贪婪的表现 :)
"虚拟构造函数机制"是一个很重要的例子,它需要一个私有或受保护的复制构造函数。在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()”间接访问。
你可能想要使用复制构造函数来实现类的某些方法,但不想将其暴露在类外部。因此,你可以将其设置为私有方法,就像其他方法一样。