如果T& A = const T& B,会破坏常量性
template<typename T>
class NameObject
{
public:
NameObject(const char* name, const T& value):nameValue(name),objectValue(value){};
NameObject(const string& name, const T& value):nameValue(name),objectValue(value){};//1
private:
string& nameValue;// const string& 2
T objectValue;
};
int main()
{
const int& a1 = 1;
int& a2 = a1; // error const会被丢弃,报错
string a{"hello"};
NameObject<int> no1(a,2);//同时注意,1中,name为const string,2中为string&没有const,不能nameValue(name)
//,编译器认为nameValue这个引用可能改变name的值
NameObject<int> no2(no1);
no1 = no2;//报错,因为nameValue是&,如果no1 = no2 则产生默认拷贝赋值操作
阻止默认构造和赋值函数生成
- 将类中的函数设置为private
- 继承一个类似于Uncopyable的函数,该函数中使用1中的设置
class Uncopyable
{
protected:
Uncopyable(){}
~Uncopyable(){}
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);
};
class A:public Uncopyable
{};
int main()
{
A tea;
A t=tea;//无法引用 函数 "A::A(const A &)" (已隐式声明) -- 它是已删除的函数
条款09 不能在构造函数和析构函数中调用virtual函数
- base构造时,子对象的成员变量尚未构造
- base class 构造期间,其derived class的类型是base class!不只是虚函数会被编译器解析至base class,若使用运行期类型如dynamic_cast和typeid,也会视为base class类型!
class testvirtual
{
public:
testvirtual()
{
init();//init 里调用了virtual,如果logtrans为纯虚,则报错,如果如例子所示,则走base里的函数
}
virtual void logtrans() const{cout<<"base"<<endl;};
virtual void logtrans1() const{cout<<"base1"<<endl;};
private:
void init()
{
logtrans();
}
};
class testvirtualdrived:public testvirtual
{
public:
void logtrans() const{cout<<"drived"<<endl;};
virtual void logtrans1() const{cout<<"drived1"<<endl;};
};
int main()
{
testvirtual tes;
tes.logtrans1();
testvirtual* tes1 = new testvirtualdrived;
tes1->logtrans1();
条款07:为多态基类声明virtual析构函数
这里需要注意的点在于:
- 需要注意一个问题,如果是正常子类继承父类,那么析构时,子类析构函数会调用父类析构函数完成对父类的析构,但是当我们用到多态时,通常是需要delete指针和引用来完成,delete base ptr是先调用base析构,然后再free,也就是说并不会调用子类的析构函数,只会调用父类的析构函数,如果是virtual,则实际调用子类析构函数,从而完成对父类的析构!
- 基类的virtual析构函数需要实现,因为子类中会调用
- 对于基类声明为virtual析构函数非必须,只有在用到多态时才必须!因为不用多态时,子类会自动调用父类析构!
- 如果用不到多态,如果强行加上virtual,则会增加虚函数表,浪费内存!
- 如果用到纯虚,则父类的析构需要有实现
class A
{public:
A(){cout<<"A"<<endl;};
~A(){cout<<"~A"<<endl;};
};
class B:public A //B会自动调用~A
{public:
B(){cout<<"B"<<endl;};
~B(){cout<<"~B"<<endl;};
};
条款11 在operator=中处理自我赋值
实现方式1:如果上图这么做,自己赋值自己,先delete第二步会无法完成
实现方法2