C VS C++

c语言是结构化模块化的语言,是面向过程的程序设计。c++既可以面向过程,也可以面向对象的程序设计(增加了面向对象机制)。c语言的头文件都有.h后缀名,c++中用户自己编制的头文件带.h,系统提供的头文件无后缀名,c++兼容c的头文件。c语言的结构体struct只能包含数据成员,c++的类可以包含数据成员和成员函数。c++中使用using namespace作为命名空间,当含有系统头文件时必须包含命名空间。


                                          C++对C的扩充


  • C++的输入输出

相比于c,c++增加了自己的输入输出流cin和cout(endl作为换行机制可以使用\n替换)。c中的scanf和printf为函数,而cin和cout为对象。cout不需要对输出数据进行格式控制,系统会自动按照数据类型输出;cin有一些格式控制功能。

  • #define 与 const的区别

  1. #define是宏定义,在预处理阶段将其定义的宏进行简单的替换,系统不会分配内存单元。const用来定义常变量,编译运行阶段系统会分配内存。
  2. define宏没有类型,编译时不做类型检查,只做简单替换。const定义的常量有类型,编译时会做类型检查
  3. define仅仅是展开,有多少地方使用就展开多少次,不分配内存。 const常量会在内存中分配(可以在堆中也可以在栈中)。注意define的替换带来的边缘效应。
  • 函数原型声明

c中函数声明(声明)时函数的返回值类型若为整形的话可以省略返回值类型,c++中不可以,但c++中函数的参数可以省略参数名,只有参数类型即可。

  • 函数的重载

c语言中,在同一作用域不能包含同名函数;c++中可以,这些同名函数中参数的个数或类型必须不同,返回值类型可以相同可以不同。(函数重载)

  • 函数模板

 函数的重载只是形参的类型或个数不同,也要分别定义。对此能否再简化呢?为了解决这个问题,C++提供了函数模板(function template)。所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只须在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。模板类声明如下:

                   template<typename T> 或template<class T>

类型参数可以不只一个,可根据需要确定个数。如 template<class T1,typename T2>

T max(T a,T b,T c)   //定义一个通用函数,用T作虚拟的类型名
{

if(b>a)a;b:
  if(c>a)a:c;
  return a:
}

  • 有默认参数的函数

多次调用同一函数时用的是同样的实参值,c++提供简单的处理办法,给形参一个默认值,这样形参就不必一定要从实参取值了。使用默认参数时注意:(默认参数具有右结合性,既默认参数的顺序必须从参数列表的右向左开始)

  1. 函数的定义在函数调用之前时,应在函数的定义中给出默认值。如果函数的定义在函数调用之后,则在函数调用之前需要有函数声明,此时必须在函数声明中给出默认值,在函数定义时可以不给出默认值。                                                             如果在声明函数时已对形参给出了默认值,而在定义函数时又对形参给出默认值,有的编译系统会给出“重复指定默认值”的报错信息,有的编译系统对此不报错,甚至允许在声明时和定义时给出的默认值不同,此时编译系统以先遇到的为准。由于函数声明在函数定义之前,因此以声明时给出的默认值为准,而忽略定义函数时给出的默认值。
  2. 一个函数不能既作为重载函数,又作为有默认参数的函数。因为当调用函数时如果少写一个参数,系统无法判定是利用重载函数还是利用默认参数的函数,会出现二义性,系统无法执行。
  • 变量的引用:

在c++中,变量的“引用”就是变量的别名。建立“引用”的作用是为一个变量起另一个名字,以便在需要时可以方便、间接地引用该变量,这就是引用名称的由来。

int a; int &b=a; 这就声明了b是a的“引用”,即a的别名。经过这样的声明后,使用a或b的作用相同,都代表同一变量。对变量声明一个引用,并不另开辟内存单元,b和a都代表同一变量单元。在声明一个引用时,必须同时使之初始化,即声明它代表哪一个变量。请注意:由于引用不是独立的变量,编译系统不给它单独分配存储单元,因此在建立引用时只有声明,没有定义,只是声明它和原有的某一变量的关系。在声明一个变量的引用后,在本函数执行期间,该引用一直与其代表的变量相联系,不能再作为其他变量的别名。

关于引用的简单说明:

  1. 引用并不是一种独立的数据类型,它必须与某一种类型的数据相联系。声明引用时必须指定它代表的是哪个变量,即对它初始化。
  2. 引用与其所代表的变量共享同一内存单元,系统并不为引用另外分配存储空间。 
  3. 当看到&a这样的形式时,怎样区别是声明引用变量还是取地址的操作呢?请记住,当及a的前面有类型符时(如int &a),它必然是对引用的声明;如果前面没有类型符(如p= &a),此时的&是取地址运算符。
  4. 对引用的初始化,可以用一个变量名,也可以用另一个引用。
  5. 引用在初始化后不能再被重新声明为另一变量的别名。

   实际上,在c++程序中很少使用独立变量的引用,如果要使用某一个变量,就直接使用它的原名,没有必要故意使用它的别名。前面举的例子只是为了说明引用的特征和基本的用法。那么有了变量名,为什么还需要一个别名呢?请见下面的介绍。

将引用作为函数参数:
   C++之所以增加“引用”,主要是利用它作为函数参数,以扩充函数传递数据的功能。在C语言中,函数的参数传递有以下两种情况。

将变量名作为实参。这时传给形参的是变量的值。传递是单向的,在执行函数期间形参值发生变化并不传回给实参,因为在调用函数时,形参和实参不是同一个存储单元。下面的程序无法实现两个变量的值互换。
 

#include <iostream>
using namespace std;
void swap(int a,int b)
  { int temp;
    temp=a;
    a=b;
    b=temp; //实现a和b的值互换
  }
int main( )
 { int i=3,j=5;
   swap(i,j);
   cout<<i<<","<<j<<endl; //i和j的值未互换
   return 0;
  }

   输出i和j的值仍为3和5。

传递变量的指针。为了解决上面这个问题,在c程序中可以用传递变量地址的方法。使形参得到一个变量的地址,这时形参指针变量指向实参变量单元。

例11 使用指针变量作形参,实现两个变量的值互换。
#include <iostream>
using namespace std;
void swap(int *p1,int *p2)
  { int temp;
    temp=*p1;
    *p1= *p2;
    *p2=temp;
  }
int main( )
 { int i=3,j=5;
   swap(&i,&j);
   cout<<i<<","<<j<<endl;
   return 0;
  }


传送变量的别名。c++把变量的引用作为函数形参,就弥补了上面的不足。这就是向函数传递数据的第三种方法,即传送变量的别名。

#include <iostream>
using namespace std;
void swap(int &a,int &b)
  { int temp;
    temp=a;
    a=b;
    b=temp;
   }
int main( )
 { int i=3,j=5;
   swap(i,j);
   cout<<"i="<<i<<" "<<"j="<<j<<endl;
   return 0;
 }

输出结果为 i=5 j=3

对引用的进一步说明:
有了以上的初步知识后,再对使用引用的一些细节作进一步讨论。
   (1)不能建立void类型的引用,如: void &a=9; //错误

因为任何实际存在的变量都是属于非void类型的,void的含义是无类型或空类型,void只是在语法上相当于一个类型而已。
   (2)不能建立引用的数组。如
      char c[6]="hello";
      char &rc[6]=c; //错误
   企图建立一个包含6个元素的引用的数组,这样是不行的,数组名c只代表数组首元素的地址,本身并不是一个占有存储空间的变量。
   (3)可以将变量的引用的地址赋给一个指针,此时指针指向的是原来的变量,如
      int a=3;   //定义a是整型变量
      int &b=a; //声明b是整型变量的别名
      int *P=&b;//指针变量p指向变量a的引用b,相当于指向a,合法
   相当于p指向变量a,即: int *p=&a;

   (4)可以建立指针变量的引用,如
      int i=5; //定义整型变量i,初值为5
      int *p=&i //定义指针变量P,指向i
      int * &pt=p;//pt是一个指向整型变量的指针变量的引用,初始化为p
   从定义的形式可以看出,&pt表示pt是一个变量的引用,它代表一个int,类型的数据对象(即指针变量),如果输出。pt的值,就是*p的值5。
   (5)可以用const对引用加以限定,不允许改变该引用的值。如
      int i=5; //定义整型变量i,初值为5
      const int &a=i; //声明常引用,不允许改变a的值
      a=3; //企图改变引用a的值,错误
   但是它并不阻止改变引用所代表的变量的值,如
      i=3; //合法    此时输出i和a的值都是3。
   这一特征在使用引用作为函数形参时是有用的,因为有时希望保护形参的值不被改变,在第3章中将会看到它的应用。
   (6)可以用常量或表达式对引用进行初始化,但此时必须用const作声明。如
      int i=5; 
      const &a=i+3; //合法
   此时编译系统是这样处理的:生成一个临时变量,用来存放该表达式的值,引用是该临时变量的别名。系统将"const= &a=i+3"转换为: int temp=1+3; //先将表达式的值存放在临时变量temp中
      const int &a=temp;//声明a是temp的别名
   临时变量是在内部实现的,用户不能访问临时变量。
用这种办法不仅可以用表达式对引用进行初始化,还可以用不同类型的变量对之初始化(要求能赋值兼容的类型)。如
      double d=3.1415926;//d是double类型变量
      const int&a=d;    //用d初始化a
   编译系统将"const int &a=d;"转换为: int temp=d; //先将double类型变量d转换为int型,存放在temp中
      const int &a=temp; //temp和a同类则
注意:此时如果输出引用a的值,将是3而不是3.1415926。因为从根本来说,只能对变量建立引用。
如果在上面声明引用时不用const,则会发生错误。如
      double d=3.1415926; //d是double类型变量
       int &a=d;         //未加const,错误
   为什么呢?若允许这样做的话,如果修改了引用a的值(例如a=6.28;),则临时变量temp的值也变为6.28,即修改了临时变量temp的值,但不能修改变量d的值,这往往不是用户所希望的,即存在二义性。与其允许修改引用的值而不能实现用户的目的,还不如不允许修改引用的值。这就是c++规定对这类引用必须加const的原因。
   c++提供的引用机制是非常有用的,尤其用作函数参数时,比用指针简单、易于理 解,而且可以减少出错机会,提高程序的执行效率,在许多情况下能代替指针的操作。在本书的第3章和第4章中会有具体的使用例子,请读者认真阅读,并在今后的实践中进一步熟悉它的使用。

  • 内置函数

调用函数时需要一定的时间,如果有的函数需要频繁使用,则累计所用时间会很长,从而降低程序的执行效率,c++提供一种提高效率的方法,即在编译时将所调用函数的代码嵌入到主函数中。这种嵌入到主函数中的函数称为内置函数(inline function),又称内嵌函数。在有些书中把它译成内联函数。指定内置函数的方法很简单,只须在函数首行的左端加一个关键字inline即可。

内置函数与用#define命令实现的带参宏定义有些相似,但不完全相同。宏定义是在编译前由预处理程序对其预处理的,它只作简单的字符置换而不作语法检查,往往会出现意想不到的错误。

  • 作用域运算符

每一个变量都有其确有效的作用域,只能在变量的作用域内使用该变量,不能直接使用其他作用域中的变量。

  • 动态分配/撤销内存的运算符new和delete​​​​​​​

在软件开发中,常常需要动态地分配和撤销内存空间。在C语言中是利用库函数malloc和free分配和撤销内存空间的。但是使用malloc函数时必须指定需要开辟的内存空间的大小。其调用形式为:malloc(size)。此外,malloc函数只能从用户处知道应开辟空间的大小而不知道数据的类型,因此无法使其返回的指针指向具体的数据。其返回值一律为void。类型,必须在程序中进行强制类型转换,才能使其返回的指针指向具体的数据。
   C++提供了简便而功能较强的运算符new和delete来取代malloc和free函数(为了与c语言兼容,仍保留这两个函数)。

new和delete是运算符,不是函数,因此执行效率高。malloc函数要和free函数配合使用,new和delete配合使用,不要混合使用(例如用malloc函数分配空间,用delete撤销)。

综上所述,c++对c功能的扩展包括:

(1)允许使用以“//”开头的注释。
(2)对变量的定义可以出现在程序中的任何行(但必须在引用该变量之前)。
(3)提供了标准输入输出流cin和cout,它们不用指定输入输出格式符(如%d),使输入输出更加方便。
(4)可以用const定义常变量。
(5)可以利用函数重载实现用同一函数名代表功能类似的函数,以方便使用,提高可读性。
(6)可以利用函数模板,简化同一类型的函数的编程工作。
(7)可以使用带默认值的参数的函数,使函数的调用更加灵活。
(8)提供变量的引用类型,即为变量提供一个别名,将“引用”作为函数形参,可以实现通过函数的调用来改变实参变量的值。
(9)增加了内置函数(内嵌函数),以提高程序的执行效率。
(10)增加了单目的作用域运算符::,这样在局部变量作用域内也能引用全局变量。
(11)可以用string类定义字符串变量,使得对字符串的运算更加方便。
(12)用new和delete运算符代替malloc和free函数,使分配动态空间更加方便。
c++对c的扩展还有其他一些方面。这些扩充使得人们在进行程序设计时,更加方便和得心应手。在本书以后各章中,将在程序中用到这些扩展的功能,读者会在实践过程中逐步熟悉和运用它们。

发布了22 篇原创文章 · 获赞 6 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/baidu_18891025/article/details/81502501
今日推荐