条款05—了解C++默默编写并调用哪些函数
对于一个C++类来说,编译器会默认生成默认构造函数,拷贝构造函数,析构函数等。例如:
class Empty
{
};
int main(int argc,char **argv)
{
Empty e1;//默认构造函数
Empty e2(e1);//拷贝构造函数
Empty e3;
e3 = e1;//赋值操作符重载
}
如果程序员编写了带参数的构造函数,那么编译器将不会自动生成默认构造函数,需要我们手动编写,否则编译器报错:
类“empty”不存在默认构造函数
对于赋值操作符重载,这里存在的陷阱:
编译错误:Error C2582
出现该错误可能有以下一些情况:
1.重载的赋值操作符被置为private。
2.编译器自动生成的重载的赋值操作符面对const或引用成员变量。
情况1
class A {
private:
A& operator=(const A& a){}
};
class B : public A {
public:
// try the following line to resolve the error
// void operator=(const B& b){}
};
int main() {
B b1;
B b2;
b1 = b2; // C2582
}
情况2
template <typename T>
class NameObject
{
public:
NameObject(string name, T obj) :nameValue(name), ObjectValue(obj){}
private:
string & nameValue;
const T ObjectValue;
};
int main(int argc, char ** argv)
{
string newDog("Persephone");
string oldDog("Satch");
NameObject<int> p(oldDog, 2);
NameObject<int> s(newDog, 36);
p = s;//c2582
}
上述代码中,首先在C++中string & nameValue
作为引用并不允许指向不同对象,另外如果这样理解,引用作为其绑定对象的“别名”因为赋值操作修改了被绑定的对象进而影响了持有了该对象的指针或引用的内容,这一点是成立的,例如:
string a="hello1";
string b="hello2";
string &ra=a;
string &rb=b;
ra=rb;
//此时a="hello2";
但是赋值操作符重载中却是不允许的,因为对象不被直接牵扯到赋值操作内。
针对上述情况1和情况2:
编译器自己生成的赋值运算符将拒绝服务,正确的做法是自己重新写一个重载的赋值运算符。
条款06—若不想使用编译器自动生成的函数,就该明确拒绝
条款06的内容就跟条款05相关了。
由编译器自动生成的默认构造函数、拷贝构造函数等是public访问的,因此,有时候就会产生这样的困惑,比如说:
在C++封装POSIX线程库中,线程是不具备拷贝和赋值语义的,在条款05中,已经知道,如果不告诉编译器,它会自动生成public访问权限的拷贝构造函数等,这个时候,程序员就该明确拒绝了,把拷贝构造函数和重载的赋值运算符显式地声明为private。如果我们又多个class(例如C++封装POSIX 互斥锁)都不需要拷贝和赋值语义,如果在每个class中都显式的去声明,那么将会增加代码量。
于是,我们可以设计一个专门阻止拷贝构造和赋值操作的基类,而所有不需要拷贝构造和赋值语义的类只需继承就好,更加幸运的是,这样的基类也不需要我们写了,boost库已经提供,参见:boost库noncopyable简介
#ifndef BOOST_NONCOPYABLE_HPP_INCLUDED
#define BOOST_NONCOPYABLE_HPP_INCLUDED
namespace boost {
// Private copy constructor and copy assignment ensure classes derived from
// class noncopyable cannot be copied.
// Contributed by Dave Abrahams
namespace noncopyable_ // protection from unintended ADL
{
class noncopyable
{
protected:
noncopyable() {}
~noncopyable() {}
private: // emphasize the following members are private
//这里private 阻止拷贝构造和赋值语义
noncopyable( const noncopyable& );
const noncopyable& operator=( const noncopyable& );
};
}
typedef noncopyable_::noncopyable noncopyable;
} // namespace boost
#endif // BOOST_NONCOPYABLE_HPP_INCLUDED
参考
Effective C++