C++对C语言的扩展

一、C++C的扩展:

1C面向过程加工的是一个个函数,C++面向对象加工的是一个个类;

2)为什么要写成员函数?

class MyCircle
{
    public :
    void setR(double d)
   {
      m_r = d;
   }
/*double getS()               //成员函数
{
   s = 3.14*m_r*m_r;
   return s;
}*/
public:
   double m_r;
   double s = 3.14*m_r*m_r;     //直接赋值
   //初始化时,m_r是个随机值,所以s也是一个随机值。当在类外直接
   //调用mycircle.s时是直接去s的内存空间拿值,并没有也不会执行
   //3.14*m_r*m_r,即使给m_r赋值,mycircle.s也仍然是个随机值。
};

3namespace(名字空间、作用域);

     所谓namespace,是指标识符的各种可见范围。C++标准程序库中的所有标识符都被定义于一个名为stdnamespace中。为了避免在大规模程序的设计中以及在程序员使用各种各样的C++库时,这些标识符的命名发生冲突,标准C++引入了关键字namespace(名字空间),可以更好地控制标识符的作用域。

   C中的命名空间:

      在C语言中只有一个全局作用域;C语言中所有的全局标识符共享同一个作用域;标识符之间可能发生冲突。  

   C++中提出了命名空间:

     命名空间将全局作用域分成不同的部分;不同命名空间中的标识符可以同名而不会发生冲突;命名空间可以相互嵌套。

namespace A
{
  int a = 10;
  namespace B
  {
     int a = 20;
  }
 
}
{
  cout << A::a << endl;     //10       
  //cout << B::a << endl;         //编译错误
  cout << A::B::a << endl;  //20
  //using namespace B;              //编译错误
  //cout << a << endl;
  using namespace A::B;              
  cout << a << endl;        //20
 
  using namespace A;        
  //cout << a << endl;      //编译错误
  cout << A::a << endl;     //10, using 关键字把名字空间里面的标识符全部暴漏
  cout << B::a << endl;     //20
 
  using namespace B;        //这时,上面的using namespace A已经将B“暴漏”,所以可以找到。
  cout << B::a << endl;     //20
}

4)实用性

     C语言的变量都必须在作用域开始的位置定义(VC6.0——》X.c)C++中更强调语言的“实用性”,所有的变量可以在需要使用时再定义。

5struct类型功能加强

     C语言的struct定义了一组变量的集合,C编译器并不认为这是一种新的类型;C++中的struct是一个新类型的定义声明。

struct Student         //在C++中,struct和class完成的功能是一样的
{
   char name[32];     //默认public,写不写无所谓
   int age;
};
 
void main()
{
  //struct Student stu;  //C语言Student stu;编译错误
  Student stu;            //C++
  stu.age = 10;
}
 

6C++中所有变量和函数都必须有类型

在C语言中:

 int f(    );表示返回值为int,接受任意参数的函数,     

         比如:f(1,2,3,4);

 int f(void);表示返回值为int的无参函数,

         比如:f();

在C++中:

 int f(  );和int f(void)具有相同的意义,都表示返回值为int的无参函数。C++更加强调类型,任意的程序元素都必须显示指明类型。

 

7C++新增bool类型关键字

    它只有0和1,没有其他值。非0都是1;

8)三目运算符

C语言中的三目运算符返回的是变量值不能作为左值使用

              (a < b ? a : b )= 30;   //编译错误

     C++本质::*(a < b ?&a : &b )= 30;

    C++中的三目运算符可直接返回变量本身能作为左值使用,可以出现在程序的任何地方。(a > b ? a : b) = 30;直接编译通过。注意:可能三目运算符返回的值中如果有一个是常量值,则不能作为左值使用:(a < b ?1 : b )= 30;

    当左值的条件:要有内存空间;C++编译器帮助程序员取了一个地址而已。

9const表现

   http://blog.csdn.net/songshimvp1/article/details/50975332 

 

(10)引用

引用——别名

     1、引用必须初始化,引用作为函数参数声明时不进行初始化。

     2、引用做函数参数的好处:

       值传递,(1)有复制操作,如果是复杂数据类型,代价比较大;(2)因为复制,也就是说形参是副本,形参和实参是两个不同的变量,对形参进行修改后,对实参不起作用。

指针,引用是变量的别名,在一些场合可以代替指针,引用相对于指针来说有更好的可读性和实用性。

     3、引用本质:

      引用有自己的内存空间,而且和指针占的内存空间大小一样。而且引用是一个常量!——Type& name——》Type* const name

     4、当函数返回值为引用时,若返回栈变量,不能成为其它引用的初始值,不能作为左值使用。

       若返回静态变量或全局变量,可以成为其他引用的初始值,即可作为右值使用,也可作为左值使用,C++链式编程中,经常用到引用,运算符重载等。

int getA1()
{
  int a;
  a = 10;
  return a;
}
 
//返回a的一个副本
int& getA2()
{
  int a;  //如果是局部变量——栈上的引用
  a = 10;
  return a;
}
 
int* getA3()
{  
  int a;
  a = 10;
  return &a;
}
 
//变量是 静态变量 或者 全局变量
int j1()
{
  static int a = 10;
  a++;
  return a;
}
int& j2()
{
  static int a = 10;
  a++;
  return a;
}
 
//函数当左值
int g1()
{
  static int b = 10;
  b++;
  return b;
}
int& g2()
{
  static int b = 10;
  b++;
  cout << b << endl;
  return b;
}
 
int main()
{
  int a1 = getA1();
 
  int a2 = getA2();
  int &a3 = getA2();  //debug版本下,这个值不稳定。(函数中栈上的变量的内存空间被搞掉了)(多测试几次)
 
  int a4 = j1();
 
  int a5 = j2();
  int &a6 = j2();
 
  cout << "a1:" << a1 << ",a2:" << a2 << ",a3:" << a3 << endl;
  cout << "a4:" << a4 << ",a5:" << a5 << ",a6:" << a6 << endl;
 
  //g1() = 100;     //编译错误
  g2() = 100;       //打印 11
  cout << g2() << endl;  //打印101 101
  return 0;
}

     5、指针引用

int m_value = 1;

void func(int *&p)      //p:  是指针的引用,main()方法里的 *pn,*p:是main()方法里的pn指向的内容。
{
    p = &m_value;

    // 也可以根据你的需求分配内存
    p = new int;
    *p = 5;
}

int main(int argc, char *argv[])
{
    int n = 2;
    int *pn = &n;
    cout << *pn << endl;
    func(pn);
    cout << *pn <<endl;
    return 0;
}

     6、常引用

const Type& name = varconst引用让变量拥有只读属性 ,不能再用name去修改var的值了。

Const int &a = 10;这种情况会单独为常量值分配内存,并将引用名作为这段空间的别名

普通引用相当于 int * const e

const  int  &e 相当于 const int* const e  

 

 

11inline内联函数

C++中内联编译的限制:不能存在任何形式的循环语句;不能存在过多的条件判断语句;函数体不能过于庞大;不能对函数进行取址操作;函数内联声明必须在调用语句之前;

编译器对于内联函数的限制并不是绝对的,内联函数相对于普通函数的优势只是省去了函数调用时压栈,跳转和返回的开销。因此,当函数体的执行开销远大于压栈,跳转和返回所用的开销时,那么内联将无意义。

内联函数在最终生成的代码中是没有定义的,C++编译器直接将函数体插入在函数调用的地方,内联函数没有普通函数调用时的额外开销(压栈,跳转,返回)inline只是一种请求,C++编译器不一定准许函数的内联请求!

内联函数由编译器处理,直接将编译后的函数体插入调用的地方;宏代码片段 由预处理器处理, 进行简单的文本替换,没有任何编译过程。

一些函数即使没有inline声明,也可能被编译器内联编译。


二、函数重载:

判断标准:相同的函数名搭配不同的参数(参数的个数不同、参数的类型不同、参数的顺序不同),函数返回值不是判断函数重载的标准。

编译器调用重载函数的准则:将所有同名函数作为候选者;尝试寻找可行的候选函数;精确匹配实参;通过默认参数能够匹配实参;通过默认类型转换匹配实参;

匹配失败:最终寻找到的可行候选函数不唯一,则出现二义性,编译失败。无法匹配所有候选者,函数未定义,编译失败。

函数重载的注意事项:重载函数在本质上是相互独立的不同函数(静态链编);函数返回值不能作为函数重载的依据;函数重载是由函数名和参数列表决定的。

   A.函数默认参数 和 函数重载结合在一起

int f(int aa, int b,int c=0)    //默认函数参数
{
   return aa + b;
}
 
int f(int aa, int b)
{
   return aa + b;
}
 

f(1, 2);=》当函数默认参数 和 函数重载结合在一起时,会发生二义性错误,无法匹配。

   B.函数重载 和 函数指针 结合

//函数重载
int func(int x)
{
   return x;
}
 
int func(int a, int b)
{
  return a + b;
}
 
int func(const char* s)
{
  return strlen(s);
}
 
//函数指针
typedef int(*PFUNC)(int); // int(int a)
 
int main()
{
  int c = 0;
  PFUNC p = NULL;   //定义一个函数指针 变量 ,用来指向函数的入口地址
  p = func;
  c = p(1);       //调用函数指针变量
  printf("c = %d\n", c);
  return 0;
}

因为函数指针在声明时,限定了参数类型和参数个数,所以在调用函数指针变量时会严格检查!

   C.

1)普通函数形参为非引用类型,非指针类型,形参一个带const,一个不带const

1 void print(int x);

2 void print(const int x); //不算重载,直接报错重定义

 

2)普通函数形参为引用类型或指针类型,一个形参带const,一个不带const

1 void print(int *x);

2 void print(const int *x); //算重载,执行正确,实参为const int *时候调用这个,为int*的时候调用上面一个

3 void print(int &x);

4 void print(const int &x); //算重载,执行正确,实参为const int &时候调用这个,为int&的时候调用上面一个

 

3)类的成员函数,形参完全相同,一个函数为const成员函数,一个函数为普通成员函数

1 void print();

2 void print() const; //算重载。const对象或const引用或const指针调用时调用这个函数,普通对象或普通引用调用时调用上面一个。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值