——effective c++ item 6 & item 5
编译器会为一个没有默认构造函数,复制构造函数,复制操作运算符的类创建它们。但是编译器创建的复制构造函数和复制操作运算符,只是单纯地将来源对象的每一个非静态成员变量拷贝到目标对象。
但是编译器还不是每次都会添加复制构造函数和赋值运算操作符。。例如
// 不能通过编译
template<class T>
class Name_obj {
private:std::string &name_value;const T obj_value;
public:Name_obj(std::string &name, const T &value): name_value(name),obj_value(value){ }// 没有声明和实现任何的复制构造函数和复制操作运算符,希望编译器会提供
};
然后用这个类写出了如下调用
std::string new_obj("foo");
std::string old_obj("grand foo");
Name_obj<int> f(new_obj, 233);
Name_obj<int> g(old_obj, 666);
f = g; // 罪恶之源。。
赋值之前f.name_value和g.name_value都会指向各自的string对象。执行到赋值的一步操作时,c++表示“不能让引用改为指向不同的对象”。
面对这个难题,编译器选择拒绝编译那一步操作。如果你打算在一个”内含 引用 成员“的类中支持赋值操作,你必须自己定义赋值操作运算符。对于”内含const 成员“的类中,编译器的反应也是一样的。
所以编译时抛出错误:使用了被删除的函数‘ Name_obj& Name_obj::operator=(const Name_obj&) ’。
因此我们还是不要让编译器自动生成代码了。。
如果你并不想要你的类支持赋值和复制。就像标准io库(iostream)里的ios_base, basic_ios,和sentry一样不支持复制行为。
编译器为你声明的方法都是public的,因此你只需要将你的方法声明为private。
class Foo {
public:private:Foo(const Foo &);Foo & operator=(const Foo &);
};
借由明确声明一个成员函数,你成功的阻止编译器暗自创建自己的版本。而且防止了别人错误的调用了它。
不过,友元函数可以调用类里面的私有方法。幸运的是,如果不慎使用友元函数调用了它,连接器会发出抱怨。其实我们可以把链接期错误移到编译器,而且这是件好事。(毕竟你不希望编译大半天,没有错误,最后连接出现错误)。
所以我们可以设计一个类专门阻止赋值和复制操作。其他类需要禁止这类操作的时候直接继承就好了。
class Uncopyable_base {
protected:Uncopyable_base() {}~Uncopyable_base() {}
private:Uncopyable_base(const Uncopyable_base &);Uncopyable_base & operator=(const Uncopyable_base &);
};// 使用的时候继承一下
class Foo : private Uncopyable_base {};
boost 下有个noncopyable。可以直接使用
#include <boost/noncopyable.hpp>
class Foo : private boost::noncopyable
{};
本文发布于:2024-01-29 17:44:46,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170652148917182.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |