首页 > 其他 > 详细

STL源码(前五款)

时间:2020-09-28 12:58:36      阅读:20      评论:0      收藏:0      [点我收藏+]

ITEM 1:(指针和引用的区别)

  • 指针和引用的区别:
    1.在任何情况下 都不能使用指向空值的引用,不存在引用的这个事实意味着引用的代码效率比使用指针的高,因为在使用前不需用测试其合法性。指针应该被测试为,放着为空。
    2.指针可以被重新赋值指向另一个不同的对象,引用则是指向在初始化时被指定的问题。
  • 使用指针和引用的情况:
    1.指针:考虑到存在不指向任何对象的可能 需要能够在不同的时刻指向不同的对象
    2.引用:与上述相反即可使用引用 还有当你需要重载某个操作符时,应该使用引用。

ITEM 2:(尽量使用c++风格类型转换)

尽量使用c++风格转换的原因:
1.c不对把一个指向const对象的指针转换成非const对象的指针 把一个指向基类的指针转换成指向子类的指针

  1. 人工阅读很肯能忽略类型转换语句,利用对象grep的工具程序也不能从语句构成上区分
    C++风格类型转换 (static_cast ,const_cast, dynamic_cast, reinterpret_cast)
    格式:eg: static_cast<type>(expression)

    static_cast:与c风格类型转换基本一样 特殊:不能把struct转换成int 或者把double转化成指针类型 (不能从表达式中去除const属性)
    const_cast:用于转换表达式中的const类型或volatileness属性

    备注:volatile属性:
    参考地址https://blog.csdn.net/weixin_44363885/article/details/92838607
    const_cast类型不能用在向子类进行类型转换

dynamic_cast:把指向基类指针或引用转换成指向其派生类或其兄弟的指针或引用,并且可以知道是否可以转换成功 失败时返回空指针(当对指针类型进行转换时) 抛出异常(当对引用类型进行转换时)

dynamic_cast:他不能用于缺乏虚函数的类型上(参考条款item24讲解(hahahaha 嗯,还没到哪里,敬请期待)),也不能用与转换掉constness属性

如果想在没有继承关系的类型中进行转换,可能是static_cast,如果为了去除const,使用const_cast

reinterpret_cast:(他的转换结果都是在执行期间,代码会很难移植)
最普遍的用途:函数指针类型之间转换

如果编译器缺乏对新类型的转换,可以使用传统的方式
语法:

            #define static_cast(TYPE,EXPR)      (TYPE)(EXPR))
            #define const_cast(TYPE,EXPR)      (TYPE)(EXPR))
            #define reinterpret_cast(TYPE,EXPR)      (TYPE)(EXPR))
    没有一个容易的方法模拟dynamic_cast操作,函数库提供了函数,
    也可回到c风格上但是不知道转换是否失败 也可以像上面一样模拟 
    但同样知道转换结果

使用:
eg: update(const_cast(SpecialWidget*,&sw));

ITEM 3:(不要对数组使用多态)
原因1
class BST{};
class BalancedBST:public BST{};

void printBSTArray(ostream& s,const BST array[].int numElements){
   s<<arrsy[i];
}

注意 参数array被声明BST类型,所以array数组中每一个元素都是BST类型,因此每一个元素与数组起始地址的建个是i*sizeof(BST) 所以后面遍历BalancedBST对象会出错

标准输入输出流只可用一农用 因为其的拷贝构造和赋值运算操作符都被删除了

原因二

void  deleteArray(ostream& logStream,BST[]){
  logStream<<"deleteing array at adress"<<static_cast<void*>(array)<<"\n";
    delete [] array
}

BalancedBST *balTreeArray=new BalancedBST[50];
....
数组被删除时,每一个数组元素的析构函数也会调用

for(int i=0数组元素个数;i>=0;i--){
  array[i].BST::~BST();
}

通过一个积累指针来删除一个含有派生类对象的数组,结构是不确定的

ITEM 4:(避免无用的缺省构造函数)
构造函数能初始化对象,缺省构造函数则可以不利用任何在建立对象是的外部数据初始化对象
原因一:

 class EquipmentPiece{
 public:
    EquipmentPiece(int IdNumber);
        ···
         };
    (由于这个类没有一个缺省构造函数,所以在三种情况下会有问题)
    1.建立数组时,没有一种能在建立对象数组是构造函数
    eg: EquipmentPiece p[10];
              EquipmentPiece* q=new EquipmentPiece[10];

            解决办法1:(数组定义时 提供必要的参数,不过不能再对数组上创建)
            EquipmentPiece array[]={
              EquipmentPiece(ID1);
                ···
            }
            解决办法2:利用指针数组代替一个对象数组
            typedef  EquipmentPiece* P;
            P bestPieces[10];  //或者
            P* bestPieces=new P[10];
            for(int i=0;i<10;i++){
               bestPieces[i]=new  EquipmentPiece(ID number);
            }
          缺点:1.你必须删除数组里的每个指针所指的对象,否则会发生内存泄漏     
                     2.增加了内存容量
**解决**
     为数组分配raw memory ,使用“placement new”方法,在内存中构造EquipmentPiece对象

         void *rawMemory=operator new[](10*sizeof(EquipmentPiece));
        EquipmentPiece*     bestPieces=static_cast<EquipmentPiece*>(rawMemory);
        for(int i=0;i<10;i++){
          new (&bestPieces[i]) EquipmentPiece(ID Number);
        }
“placement new 缺点”:必须手动调用数组的析构函数,然后调用delete[]来释放(已有delete/delete[]操作符,他会自动调用析构函数)
for(int i=9;i>=0;i--)
  bestPieces[i].~EquipmentPiece();
    operator delete[](rawMemory);
**原因二:**
  无法在许多基于模板的容器类中使用,因为实例化一个模板时,模板的类型参数应该提供一个缺省构造函数

设计虚基类时要提供缺省构造函数还是不提供缺省构造函数???
前提:所有的派生类在实例化时都必须给虚基类构造函数提供参数,这要求由没有缺省鼓噪函数的虚基类继承下来的派生类都必须知道并理解提供给虚基类构造函数的参数含义,有些人认为所有类都应该有缺省构造函数。他们会这样修改

    class EquipmentPiece{
    public:
    EquipmentPiece(int IdNumber=UNSPECIFIED);
        private:
          static const int UNSPECIFIED;
         };
         允许 EquipmentPiece e;(需要大所属成员函数检测ID 是否存在,且必须指出怎么犯的错误)

ITEM 5:(谨慎定义类型转换函数)
两种函数允许编译器进行转换
1.单参数构造函数
2.隐式类型转换操作符


单参构造函数 只用一个参数就可以调用的构造函数。该函数定义了一个参数,也可以定义多个参数但第一个参数后的所有参数都有缺省值
eg:Name(const String& s);
隐式类型转换运算符:operator关键字,后面跟一个类型符号,不用定义函数的返回类型
eg: class Rational{
public:
operator double( const);
};

**谨慎使用原因:**
原因1.     eg:  Rational r(1,2);
                cout<<r;
        假如忘了对Rational对象定义operator<<.按理应该打印失败但是没有,他会试图找到一个合适的隐式类型转换顺序使得函数正常运行
    解决:不适用语法关键字的等同的函数来替代转换运算符,例如可用asDouble函数代替operator  double函数
  eg:double asDouble() const;
    所以库函数中的string类型中没有包含隐式从string转换成C风格char*,而是定义了一个成员函数c_str
原因2:单参的类型转换 
     eg:class Array{
           public:
                 Array(int size);
         };
        for(int i=0;i<10;i++){
             if(a==b[i]){
                  ····
                 }
        }
    没有operator==函数是这样的类型,这时编译器注意到他能通过Array<int>构造函数能转换int为Array<int>类型
    if(a==static_cast<Array<int>>(b[i]))···  每一次循环都必须建立和释放Array<int>对象
 解决办法:
     1.最新编译器的特性 使用  “ explict  ” 关键字(拒绝为了隐式类型转换而调用构造函数,显示类型依然合法)
     2.首先要建立一个新类ArraySize,这个对象目的就是表示将要建立数组的大小,修改Array的单参构造函数,用一个ArraySize对象代替int
     eg:class Array{
               public:
                 class ArraySize{
                   public:(这里把ArraySize嵌套入Array中,为了强调他与Array一起使用,必须声明ArraySize为公有)
                      ArraySize(int numElements):theSize(numElements){}
                        int size()const {return theSize;}
                    private:
                      int theSize;
                 };

                 Array(int lowBound,int highBound);
                 Array(ArraySize size);
                 ArraySize的类通常被称为"proxy classes"(后面会对这种进行详细整理 敬请期待  哈哈哈哈)

             };

STL源码(前五款)

原文:https://blog.51cto.com/14569275/2538520

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!