aihot  2020-11-12 09:24:09  OpenCV |   查看评论   

 Effective C++笔记:实现

条款26:尽可能延后变量定义式的出现时间

有些对象,你可能过早的定义它,而在代码执行的过程中发生了导常,造成了开始定义的对象并没有被使用,而付出了构造成本来析构成本。

所以我们应该在定义对象时,尽可能的延后,甚至直到非得使用该变量前一刻为止,应该尝试延后这份定义直到能够给它初值实参为止。

这样做的好处是:不仅可以避免构造(析构)非必要对象,还可以避免无意义的default构造行为。

遇到循环怎么办?此时往往我们会有两个选择:

做法A:1个构造函数+1个析构函数+n个赋值操作 // 在循环外面定变量,在循环内赋值

做法B:n个构造函数+n个析构函数   // 在循环内定义并初始化变量

这时候要估计赋值的成本低还是构造+析构的成本低,另外值得考虑的是对象作用域的问题。

条款27:尽量少做转型动作

转型语法通常有三种不同的形式:

1,C风格的转型动作:(T)expression

2,函数风格的转型动作:T(expression)

3,上面的第二种被称为“旧式转型”,C++提供了四种新式转型:

const_cast<T>(expression)  //通常用来将对象的常量性转除

dynamic_cast<T>(expression)  // 转换为子类,用来决定某对象是否归属继承体系中的某个类型,但是耗费重大运行成本

reinterpret_cast<T>(expression) // 执行低级转型,实际动作取决于编译器,这也就表示它不可移植。如将一个point to int 转型为一个int

static_cast<T>(expression)  // 强迫隐式转换

在很多派生类的设计中,派生类的virtual函数需要去调用基类的virtual函数,下面是一个例子,window是一个基类,它定义了一个虚函数onResize,而Special Window是一个派生类。

class Window { public:     virtual void onResize(); };  class SpecialWindow :public Window { public:     virtual void onResize()     {         static_cast<Window>(*this).onResize(); // 将*this转型为Window,然后调用其onResize         // ... SpecialWindow专属动作     } };

但是代码中的相通过转型来调用基类的virtual函数,事实上static_cast<Window>(*this).onResize()调用的是一个*this的基类成份的一份拷贝的onResize函数,所以onResize操作所能影响到的成员只属于一个临时对象。解决的办法是把转型拿掉即可,替换成Window::onResize()。

请记住:

如果可以,尽量避免转型,特别是在注重效率的代码中避免dynamic_cast。如果有个设计需要转型动作,试着发展无需转型的设计。

如果转型是必需要,试着将它隐藏于某个函数背后。客户随后可以调用该函数,而不需将转型放进他们自己的代码。

宁可使用C++style(新式)转型,不要使用旧式转型,前者很容易被辨识,而且也比较角着分门别类的职掌。

条款28:避免返回handles指向对象的内部成分

class Point { public:     Point(int x, int y);     void SetX(int newVal);     void SetY(int newVal); private:     int x_cor;     int y_cor; };  struct RectData {     Point ulhc;    // 矩形左上角的点     Point lrhc;    // 矩形右上角的点 }; class Rectangle { private:     shared_ptr<RectData> pData; public:     Point& upperLeft()const{ return pData->lrhc; }     Point& lowerRight()const{ return pData->ulhc; } };

上面的代吗中Point是表示坐标系中点的类,RectData表示一个矩形的左上角与右下角点的点坐标。Rectangle是一个矩形的类,包含了一个指向RectData的指针。

我们可以看到了uppLeft和lowerRight是两个const成员函数,它们的功能只是想向客户提供两个Rectangle相关的坐标点,而不是让客户修改Rectangle。但是两个函数却都返回了references指向了private内部数据,调用者于是可以通过references更改内部数据。

这给了我们一些警示:成员变量的封装性只等于“返回其reference”的函数的访问级别;如果const成员函数传出一个reference,后者所指数据与对象自身有关联,而它又被存储于对象之外,那么这个函数的调用者可以修改那笔数据。

handles(号码牌,用于取得某个对象)指reference、指针和迭代器,它们返回一个“代表对象内部数据”的handle。

我们可以对上面的成员函数返回类型上加上const来解决问题:

public:     const Point& upperLeft()const{ return pData->lrhc; }     const Point& lowerRight()const{ return pData->ulhc; }

但是函数返回一个handle代表对象内部成分还总是危险的,因为可能会造成dangling handles(空悬的号牌)。比如某个函数返回GUI对象的外框(bounding box)。

class             
          
  
 

除特别注明外,本站所有文章均为 人工智能学习网 原创,转载请注明出处来自Effective C++笔记:实现

留言与评论(共有 0 条评论)
   
验证码: