• More Effective C++学习笔记(6)


    条款32:在未来时态下发展程序

    • 事情总是会改变”是一个事实,因此我们写的程序也应该在保证当下程序功能完全实现的前提下,对未来的扩展变化有所预期的进行设计,而不是简单地只完成当下的程序功能任务。Effective C++和More Effective C++的条款中有许多是帮助你的程序在未来可以轻易实现扩展的技巧。
    • 为了强化其他人理解并修改你的程序,避免错误使用,撰写注释只是很浅薄的一层,万一没有被使用者或修改者注意。更好的做法是“以C++本身”阻止或限制某些行为,例如之前条款中有阻止类派生,阻止对象产生或不产生于heap内等等
    • 请努力写出可移植的代码
    • 好好利用封装,使"系统改变所带来的冲击"得以局部化
    • 标准String类型只有非虚析构函数,因此不要以其作为基类派生出别的类
    • 如果类作为一个基类,一般情况下应当给他配一个虚析构函数

    条款33:将非尾端类设计为抽象类

    • 对具有继承体系的对象采用指针互相赋值可能存在一些难以避免的问题,例如基类有数据成员(具体类),用两个基类指针p1,p2指向两个不同的派生类对象,再用指针访问对象互相赋值*p1 = *p2,只会改变p1派生类对象中的基类部分,p1对象派生体系中派生类自己独有的部分并未被p2所指对象赋值,这有时会和我们直观上的理解意思(把一个派生类对象赋值给另一个派生类对象)不符,从而出现错误。
    • 最好的做法就是,如果两个具体类需要建立继承体系(有具体类被当作基类),那么两者肯定有相似之处,完全可以将两个类中的共同或相似部分抽象出来,作为一个新的抽象类(可以将析构函数设为纯虚函数),让两个具体类继承于它。这样利于提升软件的健壮度和扩充度。

    条款34:如何在同一个程序中结合C++和C

    • 名称重整:C++编译器往往会自动将函数名重整(例如将abc()重整为xyz()),保证所有函数名称独一无二。但C编译器不会进行重整,同一个函数单独分别在C中编译后的函数调用码和C++中编译后,函数调用码很有可能不一样,从而链接时发生错误。通过在C++函数声明前加入extern “C”,可压抑C++的名称重整。
    // this function is in assembler — don't mangle its name
    extern "C" 
    void twiddleBits(unsigned char bits);
    
    • 1
    • 2
    • 3
    extern "C" {                           // disable name mangling for
                                           // all the following functions
      void drawLine(int x1, int y1, int x2, int y2);
      void twiddleBits(unsigned char bits);
      void simulate(int iterations);
      ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    #ifdef __cplusplus
    extern "C" {
    #endif
      void drawLine(int x1, int y1, int x2, int y2);
      void twiddleBits(unsigned char bits);
      void simulate(int iterations);
      ...
    #ifdef __cplusplus
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • Statics的初始化:静态的类对象和定义在全局的、命名空间中的或文件体中的类对象的构造函数通常在main被执行前就被调用。这个过程称为静态初始化。这和我们对C++和C程序的通常认识相反,我们一直把main当作程序的入口。同样,通过静态初始化产生的对象也要在静态析构过程中调用其析构函数;这个过程通常发生在main结束运行之后。由于C中不认识对象的构造与析构,因此尽量在C++代码中写出main函数,可以调用C中的realmain()。
    extern "C"                                // implement this
    int realMain(int argc, char *argv[]);     // function in C
    int main(int argc, char *argv[])          // write this in C++
    {
      return realMain(argc, argv);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 动态内存分配:只要new分配的内存使用delete释放,malloc分配的内存用free释放,那么就没问题。用free释放new分配的内存或用delete释放malloc分配的内存,其行为没有定义。注意,有些非标准库函数可能里面有用到动态内存分配,需要明确该函数分配内存。
    • 数据结构的兼容性:C中不存在类与类成员,因此为了实现C++和C数据结构兼容,可以借用指针和函数指针。一般情况下,C++的struct内存布局和C一样。但是如果C++的struct有了虚函数,那么内存布局就会发生变化,两者则不兼容。

    条款35:让自己习惯于标准的C++语言

    学习并实践新的C++语言特性、模板特性、异常处理机制、转型、内存分配、标准模板库STL等等。

  • 相关阅读:
    炎炎夏日,清凉上线:博客园T恤丝光棉款上架预售
    《阿里云天池大赛赛题解析》——O2O优惠卷预测
    【Python】列表生成式应用的八重境界
    利用高速光耦合器增强工业自动化发展
    vscode远程连接及调试
    基于ssm+vue设备配件检修管理系统
    看起来是线程池的BUG,但是我认为是源码设计不合理。
    PX4 gazebo仿真修改步长
    全文检索&ElasticSearch简介
    使用 EMQX 接入 MQTT-SN 协议设备
  • 原文地址:https://blog.csdn.net/weixin_44248258/article/details/132778788