【effective c++】实现

1.尽可能延后变量定义式的出现时间

应该延后变量的定义,直到能够给它初值为止.这样不仅能够避免构造(和析构)非必要对象,还可以避免无意义的default构造行为

方法A:一个构造函数 + 1个析构函数 + n个赋值操作

Widget w;
for (int i = 0; i < n; ++i)
{
    w = value;
    //...
}

方法B:n个构造函数 + n个析构函数

for (int i = 0; i < n; ++i)
{
    Widget w(value);
    //...
}

通常采用方法B,方法A中w的作用域比做法B大

2.尽量少做转型动作

const_cast通常用来将对象的常量性移除,它是唯一有此能力的c++-style转型操作符

dynamic_cast主要用来执行安全向下转型,比如将指向基类的指针或引用类型转换为指向派生类的指针或引用,dynamic_cast的许多实现版本执行速度相当慢,在注重效率的代码中要尽量避免dynamic_cast

static_cast用来强迫隐式转换,比如将non-const对象转为const对象,但它无法将const转为non-const

class Window
{
public:
    Window()
    {
        width = 2;
        height = 2;
    }
    virtual void onResize()
    {
        width = 10;
    }

    int width;
    int height;
};

class SpecialWindow :public Window
{
public:
    virtual void onResize()
    {
        /*
        在当前对象的base class成分的副本上调用Window::onResize,然后在当前对象身上执行SpecialWindow专属动作。如果Window::onResize
        修改了对象内容,当前对象没被改动,改动的是副本,然后SpecialWindow::onResize内如果也修改对象,当前对象会被改动
        */
        //若只是想在派生类中调用基类版本的onResize函数,用下面的代码
        //Window::onResize();
        static_cast<Window>(*this).onResize();
        height = 3;
    }
};

int main()
{
    SpecialWindow sw;
    sw.onResize();
    cout << sw.width << " " << sw.height << endl;//输出2 3

    system("pause");
    return 0;
}

3.避免返回handles(reference、指针、迭代器)指向对象内部成分

遵守这个条款可增加封装性防止handles指向不存在的对象

4.为"异常安全"而努力

异常安全函数提供以下三个保证之一:

基本承诺:如果异常被抛出,程序内的任何事物仍然保持在有效状态下,但具体哪个状态不可预料

强烈保证:如果异常被抛出,程序会回复到调用函数之前的状态,能够通过copy-and-swap实现,但强烈保证并非对所有函数都可实现或具备现实意义

不抛掷(nothrow)保证:承诺绝不抛出异常,因为它们总是能够完成它们原先承诺的功能。作用于内置类型(如int,指针等)身上的所有操作都提供nothrow保证.

5.透彻了解inlining的里里外外

inline函数背后的整体思想是,将对此函数的每一个调用都以函数本体替换,免除函数调用成本,但过度热衷inlining会造成程序体积太大

inline只是对编译器的一个申请,不是强制命令。这项申请可以隐式提出,也可以明确提出。隐式方式是将函数定义于class定义式内(包括成员函数和友元函数)

inline函数无法随着程序库的升级而升级,如果f是程序库内的一个inline函数,客户将f函数本体编进其程序中,一旦程序库设计者决定改变f,所有用到f的客户端程序都必须重新编译。而如果f是non-inline函数,一旦它有任何修改,客户端只需要重新连接就好,远比重新编译的负担少很多。

大部分编译器拒绝将太过复杂(带有循环或递归)的函数inlining,而所有对virtual函数的调用都会使inlining落空.virtual意味着等待,直到运行期才确定调用哪个函数,inline意味着执行前,先将调用动作替换为被调用函数的本体

6.将文件间的编译依存关系降至最低

6.1. 如果使用object references或object pointers可以完成任务,就不要使用objects.你可以只靠一个类型声明式就定义出指向该类型的references和pointers;但如果定义某类型的objects,就需要用到该类型的定义式

6.2. 如果能够,尽量以class声明式替换class定义式.当你声明一个函数而它用到某个class时,你并不需要该class的定义,纵使函数以by value方式传递该类型的参数(或返回值)亦然

6.3. 为声明式和定义式提供不同的头文件

posted @ 2016-09-11 15:25  合唱团abc  阅读(237)  评论(0编辑  收藏  举报