c++笔记

来源:互联网 发布:太原新医医院网络平台 编辑:程序博客网 时间:2024/06/11 17:02

引用不能为空

  无法定义一个什么都不引用的引用

    - int& r = NULL;  //error

  "野引用"或者"悬空引用"确实是存在的

  - int & r = *new int(1);

    ++r;

    cout<<r<<endl;      //2

    delete &r;

    ++r;   //未定义

  解引用一个野引用,就跟解引用一个野指针一样,其结果将是未定义的,可能导致崩溃(段错误),可能意外地修改了其他有效堆内存中的数据,也可能什么也没有发生而且结果还很正确,但没有人能保证到底会是哪种结果.

引用不能更换目标

  引用一经初始化便不能再引用其他对象

     -int a = 10,b = 20;

      int& c =a;  //c是a的引用,a是c的目标

      c = b;    //将b的值赋值给c的目标即a,而非令c引用b

  引用只有在其定义及初始化语境中具有"名"语义,一旦完成了定义以及初始化,引用就和普通变量名一样,被赋予了"实"语义,即代表它的目标,而不是别名本身.

  引用型参数

函数的形参是实参的别名

   可以将函数的形参声明为引用形式,该形参在参数传递过程中由对应位置的实参初始化,并成为该实参的别名

     -void fun(int& formal){

         cout<<&formal<<":"<<formal<<endl;

     }

     

     -int actual = 10;

      cout<< &actual<<":"<<actual<<endl;

      fun(actual);

在函数中修改实参值

 .通过引用型形参,可以在函数体内部修改调用者实参的值,成为除返回值和指针参数之外,第三种由函数内部向函数外部输出数据的途径

  -double rect(double w,double h,double* c,double& s){

   *c = (w+h)*2;

    s=w*h;

    return sqrt(w*w+h*h);

   }

  -double c,s,d=rect(4,3,&c,s);

   cout<<"对角线长度:"<< d <<endl;

   cout<<"矩形的周长:"<< c <<endl;

   cout<<"矩形的面积:"<< s <<endl;

 

避免对象复制的开销

  通过引用传递参数,形参只是实参的别名而非副本,这就避免了从实参到形参的对象复制,这对于具有复杂数据结构的参数类型而言意义非常

   -struct User{

     char name[64];

     char address[256];

     char mbox[128];

  }

   -void insert (User& user){...}

   -User user = {...};

     insert(user);

防止对实参进行意外的修改

  即便所传递的实参不是常量,只要根据设计,函数不需要也不应该对该实参做任何修改,那么接收该实参的形参同样可以被声明为常引用,这样一方面避免了对象复制的开销,同时一旦做出对实参意外修改,将直接引发编译错误,将修改实参所带来的风险降到最低

  -int sum(int const& x,int const& y){

  ++x;//错误

  y+=100;//错误

  rreturn x+y;

  }

  -int a=20,b=30,c=sum(a,b);

 

接收常量型实参

1.在c++中,一切常量均带有右值属性

2.用内容只读的右值对象初始化目标可写的左值引用,将被编译器以轻松类型限定为由予以拒绝

3.常引用型的形参因其对目标的只读性约束,满足了编译器类型限定从紧不从松的原则,可以接受常量型实参

4.c++98中只有左值引用没有右值引用,因此只能用常左值引用引用右值当然常左值引用也能引用常或非常左值,故该引用又被称为万能引用

  -int sun(int const& x,int const& y){return x + y;}

   -int a=20,b=30,c=sum(10,a-b);

 //字面值常量10是纯右值,a-b表达式的值是将亡右值

引用型返回值

 函数的局部变量只具有函数甚至块或者语句级声明周期,函数一旦返回,所有的局部变量即刻销毁,即使通过返回值获得了对它们的引用,其目标也将是未定义的

  -int& foo(void){int n=123;return n;}   //危险

   int* bar(void){int n=456;return &n;}   //危险

   int hum(void){int n=789;return n;}

  -int& foo(int& n){return n;}

   int& bar(int* n){return n;}

   int& hum(int n){return n;}              //危险

  -int* foo(int& n){return &n;}

   int* bar(int* n){return n;}

   int* hum(int n){return &n;}               //危险

返回右值

 1.值形式的函数返回值天然具有右值属性,但从函数返回值跟通过值向函数传参数一样,伴随着对象的复制过程

  -int foo(void){...}

   foo()=1234;    //错误

 2.为了避免对象复制的开销,同时又不想失去作为函数返回值的右值属性,可以返回一个常左值引用,模拟或者逼近右值的使用效果

   -int& foo(void){...}

    foo() =1234;

   -int const& foo(void){...}

    foo() =1234;    //错误

归纳:

.引用

1.定义:引用即别名

2.语法:

 目标类型& 引用标识符=目标变量      

eg:

  int b;

  int& a=b;

//int &a = b;

//int & a =b;形式比较多

常引用:const int& c = b;

       int const& c=b;

char const* p;

char *const p;

const char* p;   //等价于 char const* p;

3.引用必须在定义的时候初始化

4.不能定义什么都不引用的引用,也不能用NULL来初始化引用

5.引用一经定义就不能在引用别的变量

6.引用型的函数参数:

   1.通过引用型参数输出数据

   2.借助于引用型参数避免按值传参过程中内存复制的开销

7.引用型返回值

   1.返回左值

   2.避免返回值的过程中内存复制的开销;

8.引用和指针的区别

   1.指针可以用空初始化

   2.指针可以改变指针所指向的目标,引用不可以

   3.可以定义指向指针的指针,但是不可以定义引用的引用

    && -在c++98中非法;   c++11中合法,但他并不表示二级引用,而是表示右值引用

            为什么:因为引用本身并不是一个实体,它是一个别名并不占地址,所以不能被引用;

   4.可以定义引用指针的引用,但是不可以定义指向引用的指针

   int* p;

   int*& r=p;

   

   int a;

   int& r=a;

   ing &*p=&r;(x)

   5.可以定义指针数组,但是不可以定义引用数组,却可以定义数组引用;

       int * p[5];

       int & ra[5];   //错误

数组引用:int(&ar)[5]=a;

数组指针:inti(*ap)[5]=&a;

9.引用的本质就是指针!引用还是通过指针实现的

 

显示类型转换

c语言的显式类型转换

  int  i;

  char c=(char)i;

 

  void* pv=...;

  int* pi=(int*)pv;

c++中有四种显式类型转换

1.静态类型转换

static_cast<目标类型>(源类型对象)

  编译器对源类型和目标类型做相容性检查,检查不通过报错

  源类型和目标类型只要在一个方向上可以做隐式类型转换,那么在两个方向上就都可以做静态类型转换

  如果将目标类型从源类型的类型转换构造函数,或者源类型向目标类型的类型转换运算符函数,被声明explicit,那么从源类型到目标类型的类型转换就必须是显式完成,静态类型转换可以用于这种场合

例如:int* pi=static_cast<int*>(pv);

2.动态类型转换

daynamic_cast<目标类型>(源类型对象)

  编译器首先检查源类型和目标类型是否为同指针或引用且其类型之间存在具有多态性的继承关系,不存在直接报错

  编译器生成一段指令,运行时执行该命令,检查源和目标的类型是否一致,不一致通过返回空指针或抛出异常报错

  常被用于具有多态继承关系的父子类对象的指针或引用之间的转换

 

3.去常类型转换

const_cast<目标类型>(源类型对象)

  编译器检查源类型和目标类型是否同为指针或引用,且其目标类型之间除常属性之外必须完全相同,否则直接报错

  去除指针或引用上的const属性

   int const volatile x=100;

   int const* p=&x;

   *p=200; //错误

   int* q=const_cast<int*>(p);

   *q=200;

4.重解释类型转换

  reinterpret_cast<目标类型>(源类型对象)

  编译器检查源类型和目标类型是否为指针或引用,或者一个是指针一个是整型,否则直接报错

  在任意类型的指针或引用之间转换,意味着可以将同一个对象视作不同的类型,并以不同的方式,访问或者处理

  无论何种类型的指针,从本质上讲都是与整数无异,即地址空间中一个特地个字节的顺序号

 

  

归纳:

.显式类型转换

1.静态类型转换

static_cast:隐式类型转换的逆转换.自定义类型转换

2.动态类型转换

dynamic_cast:多态继承的父子类指针或引用

3.常量类型转换

const_cast:去除指针或者引用的常属性

4.重解释类型转换

reinterpret_cast:不同类型的指针或引用,以及指针和整型之间的转换

 

类和对象

   类是一种用户自定义的符合数据类型,即包括表达属性的成员变量,也包括表达行为的成员函数

类和结构

 c++中类和结构已经没有本质性的差别,唯一的不同在于

   1.类的缺省访问控制属性为私有(private)

     class Dummy{int m_var;};

     等价于:

      struct Dummy{private: int m_var;};

   2.结构的缺省访问控制属性为共有(public)

      struct Dummmy{int m_var;};

       等价于

      class Dummy{public: int m_var;};

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

原创粉丝点击