笔记
effective C++ 读书笔记
5、 了解类中默默实现了哪些函数
如果自己没有定义,编译器会自动定义4个函数:构造函数、析构函数、拷贝赋值运算符(A operator=(const A& a) )和拷贝构造函数(A(const A& a))
但是以下情况不会默认生成默认的拷贝赋值运算符:
1、类中含有引用的成员变量
2、类中含有const的成员变量
class Foun
{
private:
std::string& str; //引用变量初始化后不允许再指向别的变量
const int num; //const成员不可更改
}
解决办法:自定义拷贝构造函数和赋值构造运算符
6、 不想使用类提供的默认函数,就要明确拒绝
做法:将对应的成员函数声明为private,且不予实现
class Foun
{
private:
Foun(const Foun&);
Foun& operator=(const Foun&)
}
7、为多态基类声明virtual析构函数
我们先看一种错误的代码情况
class Animal
{
private:
Animal();
~Animal();
}
class Cat: public Animal{}; //子类Cat
class Dog: public Animal{}; //子类Dog
//getAnimal是一个工厂函数,返回的base指针,指向子类对象
Animal *p = getAnimal();
delete p;
上诉代码,被delete的p是基类对象,基类的析构函数调用,而子类的析构函数未被调用,导致“局部销毁”,引发内存泄漏。
解决办法如下:
class Animal
{
private:
Animal();
virtual ~Animal(); //为多态基类声明virtual析构函数。
}
当类不被作为基类时,那么类中就不要含有virtual函数。
- 带有虚函数的话。对象中会有一个占空间的虚函数指针,指向虚函数表(vtbl),导致对象大小变化,引发不必要的问题。
- 不带虚函数的类不要作为基类,如string、STL
类中只要带有virtual函数,就要有一个virtual析构函数.
别让异常逃离析构函数
C++不喜欢析构函数吐出异常,如果析构函数吐出了异常,析构函数应该捕捉记录 异常,然后吞下它们或者结束程序。不能让异常逃离析构函数。
class DBConnection
{
public:
static DBConnection create();
void close();
}
为确保用户不忘记调用close,合理的做法是创建一个管理DBConnection的类,如下
class DBMnage
{
public:
void close() //用户操作接口close
{
db.close()
closed = true;
}
~DBManage()
{
if(!close)
{
try(db.close()) //捕捉异常并处理
catch(...)
{
log.....
}
}
}
private:
DBConnection db;
bool closed;
}
如果用户需要对某个函数操作运行期间抛出的异常做处理,那么class应该提供一个普通函数执行该操作(若用户未处理,则析构函数粗暴处理)
禁止在析构函数和构造函数中调用virtual函数
为什么
声明一个子类对象,base类的构造造函数先调用,此时derived类的成员变量和成员函数尚未初始化,base类构造期间的virual函数不会下沉到derived阶层。析构函数同理,一旦derived析构函数开始执行,对象内的derived成员函数便呈现未定义值。进入base class析构函数后的对象,就成为一个base类对象。
如果非要这样做呢?
可以将base类的virtual改为non-vritual,然后让derived的构造函数传递信息给base类的构造函数。
Class Anamal
{
public:
Anamal(const std::string& str)
{
Charac(const std::string& str);
};
void Charac(const std::string& str) const;
}
Anamal(const std::string& str)
{
Charac(const std::string& str);
};
Class Dog::public Anamal
{
public:
Dog(para…):Anamal(create(para……))
{
……;
};
private:
static std::string creaetStr(……);
}
让operator=返回一个reference to *this
Widget& operator=(const Widget& rhs)
{
// Todo
return *this;
}