C++知识点积累(2)

点点圈 提交于 2019-12-17 13:00:26

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

        1  如果出于某些原因,需要在const成员函数中修改某一个或几个成员,那么可以将需要修改的成员声明为mutable,例如

  class A
  {
  public:
      int m_cannotBeModified;
      mutable int m_needToBeModified;
      void ModifyMutable() const
      {
          m_needToBeModified = 1;  //合法
          m_cannotBeModified = 1;  //不合法
      }
  };

        2  如果一个类没有显式声明构造函数,拷贝构造函数,赋值运算符,析构函数,编译器会相应地合成一个,如果类显式定      义了任何一个构造函数,包括拷贝构造函数,编译器就不会再合成构造函数。        
        3  要阻止一个类对象拷贝或赋值,可以声明一个简单的基类,基类中将拷贝构造函数和赋值运算符声明为private,这样其派生类的拷贝或赋值操作在编译期就可以被检查出来。例如:

class A
{
protected:
    A(){}
    ~A(){}
private:
    A(const A& a){}
    A& operator=(const A&a){}
};
class B : public A
{
};
int main()
{
    B b;
    //B b1(b);                //编译不通过
    //B b2 = b;               //编译不通过
    B b3;
    //b3 = b;                 //编译不通过
    return 0;
}

        如果B不继承自任何类,直接把其拷贝构造函数和赋值运算符声明为private,并定义,那么类外不能做拷贝或赋值操作, 类内部或友元函数或友元类仍可做拷贝或赋值操作。
        如果B不继承自任何类,直接把其拷贝构造函数和赋值运算符声明为private,不提供定义,那么类外不能做拷贝或赋值操作,类内部或友元函数或友元类要做拷贝或赋值操作的话,链接期会发现错误,因为没有提供定义。
        4  如果在基类的构造函数中调用虚函数,那么虚函数绝不会下降到派生类阶层,调用的仍是基类本身的虚函数,这时虚函数并没有表现得像虚函数。派生类对象在基类构造期间,其对象类型就是基类,其运行时类型信息也属于基类,在进入派生类构造函数前绝不会成一个派生类对象。
        5  使用引用计数型智能指针shared_ptr可以有效管理资源,但如果使用shared_ptr时出现了环状引用,还是会导致内存泄露例如下面的代码,程序退出后,new出来的A和new出来的B的引用计数都仍然是1,堆上的内存空间都不会释放。

class B;
class A
{
public:
  shared_ptr<B> m_b;
};
 
class B
{
public:
  shared_ptr<A> m_a;
};
 
int main()
{
  shared_ptr<A> a(new A);       //new出来的A的引用计数此时为1
  shared_ptr<B> b(new B);       //new出来的B的引用计数此时为1
  a->m_b = b;                   //B的引用计数增加为2
  b->m_a = a;                   //A的引用计数增加为2
}

         再例如下面的代码,主函数退出后,new出来的CCycleRef引用计数为1,内存无法释放:

class CCycleRef  
{  
public:  
    ~CCycleRef()  
    {  
        cout <<"destroying CCycleRef"<<endl;  
    }  
  
public:  
    shared_ptr<CCycleRef> selfRef;  
};  
  
void CycleRefTest()  
{  
    shared_ptr<CCycleRef> cyclRef(new CCycleRef());  
    cyclRef->selfRef = cyclRef;   
}  
  
int _tmain(int argc, _TCHAR* argv[])  
{  
    CycleRefTest();  
    return 0;  
}

        解决办法是使用弱智能指针定义类中的智能指针成员,即将类中的shared_ptr换成weak_ptr即可。        
        6  前置自增运算符返回的是操作数加1后的值,返回的是操作数本身,是一个左值后置自增运算符返回的是操作数加1前的值,其操作数可以理解为值与原操作数相等的一个常量,是一个右值。
       重载前自增运算符和后自增运算符时,要保证其语义与全局的前自增运算符和后自增运算符的语义相同,即前自增返回一个左值,后自增返回一个右值。所以重载的前自增运算符通常返回该对象的引用,以支持++++obj这样的操作;重载的后自增运算符通常返回该类的一个常量对象,防止出现obj++++这样的操作。
       例如下面的代码:

class A
{
public:
    A(){ m_num = 0; }
    A& operator++()
    {
        ++m_num;
        return *this;
    }
    const A operator++(int i)
    {
        A temp(*this);
        ++*this;
        return temp;
    }

public:
    int m_num;
};

​

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!