• MoreEffectiveC++Item35(基础议题)(条款1-4)



    条款1:区别指针和引用

    条款2:最好使用C++转换操作符

    条款3: 绝对不要以多态的方式处理数组

    条款4: 避免无用的缺省构造函数


    条款1:区别指针和引用

    1.指针(pointer) 使用[*/->]

     引用(reference) 使用[.]

    2.a.引用没有null

       b.引用必须初始化

     c.引用不可以被重新赋值

    3.引用比指针的效率更高(其实只是更安全),引用不需要判定是否为null 

    总结: 指向不变用引用


    条款2:最好使用C++转换操作符

    C的强制转换是一定会实现,但是并不保证强转后的结果是否正确.而且可读性差.C++封装了这C的强转并且提高了强转的安全性.

    下面简单介绍一下C++的四种强制转换

    1.static_cast 用于普通类型的转换(int,char...) [类似于 int const *p 不可以用static_cast<>]

    2.const_cast 去除const属性 [eg:const char *pc=" HDU"; char *p=const_cast<char *>(pc);]

    3.dynamic_cast 多态之间类型转换 转换指针失败时返回null

                     转换引用失败时抛出bad_cast

                     转换类型失败时返回 0

    4.reinterpret_cast 指针类型间的转换 


    条款3: 绝对不要以多态的方式处理数组

    class Base{ ... };(size: 4)// 假设大小为4

    class Driver: public BASE{ ... };(size: 6)//子类一般会比父类多一些data 所以一般的子类都会比父类大一些

    void printArray(ostream& s,const Base array[],int numElements){

    {

      for (int i = 0; i < numElements; ) {

      s << array[i]; 

      }

    }

    如果用 Base BaseArray[10] 调用该函数 会正常运行

    如果用 Driver DriverArray[10] 去调用该函数 会通过编译 但是后果却不可预估

    我们仔细想一想 array[i]代表的意义是 *(array + i)  它的步长是 i*sizeof(数组中的对象) 在该函数 步长为4

    BaseArray它的大小是4 可以正常调用此函数  然而DriverArray的步长是6  循环后会造成一种不可预估的错误


    条款4: 避免无用的缺省构造函数

    不提供默认构造函数是为了防止创建出无意义的类

    1 class Person{
    2 public:
    3 Person(int IDCard);
    4 ...
    5 };

    由于Person缺少默认构造函数,其运行时可能在3种情况下出错

    1.创建数组时 

    1 Person person[10]; //错误无法调用正确的默认构造函数
    1 Person * person = new Person[10];//错误 同上

     解决方案:

    a:

    1 int ID1,ID2,ID3,ID4...ID10
    2 Person person[] = {
    3 person(ID1),
    4 person(ID2),
    5 ...
    6 Person(10)}// 使用non-heap数组 缺点:无法延伸至heap数组 创建1000个需初始化1000次

    b:

     1 tepedef Person * p;// p是指向Person的一个指针
     2 p array[10];
     3 p * array = new p[10];
     4 for (int i =0; i<10;i++)
     5 {
     6       p[i] = new Person[IDCard];
     7 }
     8 //两个缺点手动删除指针,需创建容纳指针的内存,详情见条款8

    c:

     1 void *rawMemory =operator new[](10*sizeof(Person));
     2 Person *person =static_cast<Person*>(rawMemory);
     3 for (int i = 0; i < 10; ++i){
     4 new (&person[i]) Person( IDCard);
     5 }
     6 //缺点需以构造顺序相反的顺序析构
     7 for (int i = 9; i >= 0; --i){
     8 person [i].~Person();
     9 operator delete[](rawMemory);
    10 }
    11 //切记不能使用普通的数组删除法
    12 //delete [] person ;//错误 person 不是new出来的 

    2.如果该类没有默认构造函数,那么它有可能不适用有些模板。如果类的设计者自定义的类模板(准确的说应该是容器模板)使用内存池的方法的话,这一个缺陷可以避免

    3.如果虚基类没有默认构造函数,则每个派生类都必须调用虚基类的构造函数.这个是不被期待的.

  • 相关阅读:
    log4j日志配置
    map和java对象的转换方法
    阿里巴巴的json使用时的一些转换方法
    HttpClient发送Post和Get请求
    IT网站导航
    python学习
    git解决冲突
    协程
    Python实现协程
    异步任务神器 和定时任务Celery
  • 原文地址:https://www.cnblogs.com/LearningTheLoad/p/6765205.html
Copyright © 2020-2023  润新知