Effective C++——构造析构等

如果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 则产生默认拷贝赋值操作

阻止默认构造和赋值函数生成

  1. 将类中的函数设置为private
  2. 继承一个类似于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函数

  1. base构造时,子对象的成员变量尚未构造
  2. 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析构函数

这里需要注意的点在于

  1. 需要注意一个问题,如果是正常子类继承父类,那么析构时,子类析构函数会调用父类析构函数完成对父类的析构,但是当我们用到多态时,通常是需要delete指针和引用来完成,delete base ptr是先调用base析构,然后再free,也就是说并不会调用子类的析构函数,只会调用父类的析构函数,如果是virtual,则实际调用子类析构函数,从而完成对父类的析构!
  2. 基类的virtual析构函数需要实现,因为子类中会调用
  3. 对于基类声明为virtual析构函数非必须,只有在用到多态时才必须!因为不用多态时,子类会自动调用父类析构!
  4. 如果用不到多态,如果强行加上virtual,则会增加虚函数表,浪费内存!
  5. 如果用到纯虚,则父类的析构需要有实现
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
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44537992/article/details/104993859