C++对C的扩充(1)

来源:互联网 发布:ubuntu wine qq 编辑:程序博客网 时间:2024/05/21 17:16

第二讲:C++对C的扩充(1)

本讲基本要求

    掌握:C++的输入、输出;定义常变量;函数原形的声明的方式;函数的重载与函数模板。
    理解:C++程序的基本构成;C与C++程序的主要区别。
    了解:C++基本程序的设计。
    重点、难点:C++的输入、输出;定义量变量;函数原形的声明的方式;函数的重载与函数模板。

一、 从C到C++
   1、问题的提出:
C语言是结构化和模块化的语言,它是面向过程的。在处理较小规模的程序时,程序员用C语言较为得心应手。但是当问题比较复杂、程序的规模比较大时,结构化程序设计方法就显出它的不足。c程序的设计者必须细致地设计程序中的每一个细节,准确地考虑程序运行时每一时刻发生的事情,例如各个变量的值是如何变化的,什么时候应该进行哪些输入,在屏幕上应该输出什么等。这对程序员的要求是比较高的,如果面对的是一个复杂问题,程序员往往感到力不从心。当初提出结构化程序设计方法的目的是解决软件设计危机,但是这个目标并未完全实现。
   2、解决方案: 为了解决软件设计危机,在20世纪80年代提出了面向对象的程序设计(object oriented programming,OOP)思想,这就需要设计出能支持面向对象的程序设计方法的新语言。Smalltalk就是当时问世的一种面向对象的语言。而在实践中,人们发现由于C语言是如此深入人心,使用如此广泛,以至最好的办法不是另外发明一种新的语言去代替它,而是在它原有的基础上加以发展。在这种形势下,C++应运而生。C++是由AT&TBell(贝尔)实验室的Bjame Stroustrup博士及其同事于20世纪80年代初在C浯言的基础上开发成功的。C++保留了C语言原有的所有优点,增加了面向对象的机制。由于C++对c的改进主要体现在增加了适用于面向对象程序设计的“类(class)”,因此最初它被Bjarne Stroustrup称为”带类的C”。后来为了强调它是C的增强版,用了C语言中的自加运算符“++”,改称为C++。
    3、标准:AT&T发布的第一个C++编译系统实际上是一个预编译器(前端编译器),它把C++代码转换成c代码,然后用c编译系统编译,生成目标代码。第一个真正的C++编译系统是1988年诞生的。C++2.0版本于1989年出现,它作了重大的改进,包括了类的多继承。1991年的C++3.0版本增加了模板,C++4.0版本则增加了异常处理、命名空间、运行时类型识别(RTTI)等功能。ANSIC++标准草案是以C++4.0版本为基础制定的,1997年ANSIC++标准正式通过并发布。但是目前使用的C++编译系统中,有一些是早期推出的,并未全部实现ANSI C++标准所建议的功能。
    C++是由c发展而来的,与C兼容。用C语言写的程序基本上可以不加修改地用 于C++,,从C++的名字可以看出它是c的超集。C++既可用于面向过程的结构化程序设计,也可用于面向对象的程序设计,是一种功能强大的混合型的程序设计语言。

    4、C++对C的“增强”,表现在两个方面:

    (1)在原来面向过程的机制基础上,对C语言的功能作了不少扩充。
    (2)增加了面向对象的机制。
    

二、最简单的C++程序

    为使读者了解什么是C++程序,下面先介绍几个简单的程序。
    例1 输出一行字符:“This is a C++ program.”。
程序如下:
    #include <iostream>      //用cout输出时需要用此头文件
    
using namespace std;     //使用命名空间std
    
int main()
    {   cout<<"This is a C++ program./n"; //用C++的方法输出一行
    
   return 0;
     }
程序运行时输出:
This is a C++ program.
   本程序和以前见过的c程序有什么不同?
   1、在C++程序中,一般在主函数main前面加一个类型声明符int,同时在main函数的最后加—条语句"return();"即可},即此主函数带回一个整型的函数值)。程序第5行的作用是向操作系统返回0。如果程序不能正常执行,则会自动 向操作系统返回一个非零值,一般为-1。
   2、在C++程序中,可以使用C语言中的“/*……*/”形式的注释行,还可以使用以“//”开头的注释。
应注意:它是单行注释,不能跨行。C++的程序设计人员多愿意用这种注释方式,它比较灵活方便。
   3、在C++程序中,一般用Cout进行输出。cout是由c和ont两个单词组成的,它是C++用于输出的语句。
   4、使用cout需要用到头文件iostream。程序的第l行"#include<iostream>”是一个预处理命令。文件iostream的内容是提供输入或输出时所需要的一些信息。iostream是i-o-stream三个词的组合
   请注意:在C语言中所有的头文件都带后缀.h(如stdio.b),而按C++标准要求,由系统提供的头文件不带后缀.h,用户自己编制的头文件可以有后缀.h。在C++程序中也可以使用C语言编译系统提供的带后缀.h的头文件,如"#include<math.h>"。
   (5)程序的第2行"using namespace std;”的意思是“使用命名空间std"。

例2 求a和b两个数之和。
可以写出以下程序:
   // 求两数之和 (本行是注释行)
   
#include <iostream> //预处理命令
   
using namespace std;//使用命名空间std
   
int main()        //主函数首部
   
{               //函数体开始
     
int a,b,sum;   //定义变量
      
cin>>a>>b;    //输入语句
      
sum=a+b;      //赋值语句
      
cout<<"a+b="<<sum<<endl; //输出语句
      
return 0;   //如程序正常结束,向操作系统返回一个零值
   
}
   
如果在运行时从键盘输入

   123 456/
则输出为

   a+b=579


例3 输入两个数x和y,求两数中的大者。
在本例中包含两个函数。
#include <iostream>
using namespace std;
int main()
 { int max(int x,int y); //对max函数作声明
   
int a,b,c;
   cin>>a>>b;
   c=max(a,b);          //调用max函数
   
cout<<"max="<<c<<endl;
   return 0;
 }

int max(int x,int y)    //定义max函数
{ int z;
  if(x>y) z=x;
  else z=y;
  return(z);
}

程序运行情况如下:
  
 18 25 / (输入18和25给a和b)
   max=25 (输出c的值)

   注意:输入的两个数据间用一个或多个空格间隔,不能以逗号或其他符号间隔。

   下面举一个包含类(class)和对象(object)的简单程序,目的是使读者初步了解C++是怎样体现面向对象程序设计方法的。由于还末系统介绍面向对象程序设计的概念,读者可能对程序理解不深,现在只需有一个初步印象即可。在第2章中将会详细介绍。

例4 包含类的C++程序。
#include <iostream>
using namespace std;
class Student        // 声明一个类,类名为Student
   
{ private:       // 以下为类中的私有部分
        
int num;    // 私有变量num
        
int score;  // 私有变量score
     
public:        // 以下为类中公用部分
        
void setdata() // 定义公用函数setdata
        
{ cin>>num;    // 输入num的值
         
cin>>score;  // 输入score的值
        
}
        void display() // 定义公用函数display
         
{ cout<<"num="<<num<<endl; // 输出num的值
          
cout<<"score="<<score<<endl; //输出score的值
         
};
   };       // 类的声明结束
Student stud1,stud2; //定义stud1和stud2为Student类的变量,称为对象

int main()       // 主函数首部
{ stud1.setdata(); // 调用对象stud1的setdata函数
  
stud2.setdata(); // 调用对象stud2的setdata函数
  
stud1.display(); // 调用对象stud1的display函数
  
stud2.display(); // 调用对象stud1的display函数
  
return 0;
}


程序运行情况如下:
   
1001 98.5 (输入学生1的学号和成绩)
   1002 76.5 (输入学生2的学号和成绩)
   num=1001 (输出学生1的学号)
   score=98.5 (输出学生1的成绩)
   num=1002 (输出学生2的学号)
   score=76.5 (输出学生2的成绩)

   通过这个例子,读者可以初步了解包含类的C++程序的形式和含义:
   说明:以上几个程序是按照ANSI C++规定的语法编写的。由于C++是从c浯言发展而来的,与C兼容。

三、 C++对C的扩充

   C++既可用于面向过程的程序设计,也可用于面向对象的程序设计。在面向过程程序设计的领域,C++继承了C语言提供的绝大部分功能和浯法规定,并在此基础上作了不少扩充,主要有以下几个方面。

(一)C++的输入输出

    C++为了方便用户,除了可以利用pfintf和scanf函数进行输出和输入外,还增加了标准输入输出流cout和tin。cout是由c和out两个单词组成的,代表C++的输出流,cin是由c和中两个单词组成的,代表C++的输入流。它们是在头文件iostream中定义的。键盘和显示器是计算机的标准输入输出设备,所以在键盘和显示器上的输入输出称为标准输入输出,标准流是不需要打开和关闭文件即可直接操作的流式文件。

C+


⑴用cout进行输出
    cout必须和输出运算符“<<”一起使用。
   “<<”在这里不作为位运算的左移运算符,而是起插入的作用,例如:“cout<<”Hello! /np;”的作用是将字符串“Hello! /n”插入到输出流cout中,也就是输出在标准输出设备上。
    也可以不用“/n”控制换行,在头文件iostream中定义了控制符endl代表回车换行操作,作用与“/n”相同。endl的含义是endofline,表示结束一行。
    可以在一个输出语句中使用多个“<<”运算符将多个输出项插人到输出流cout中,“<<”运算符的结合方向为自左向右,因此各输出项按自左向右顺序插入到输出流中。

例如:
   
for(i=1;i<=3;++)
    tout<<"count="<<i<<endl;
输出结果为
    count=1
    count=2
    count=3
注意:每输出一项要用一个“<<”符号。不能写成"cout<<a,b,c,"A";"形式。
用cout和“<<”可以输出任何类型的数据,如:
    float a=3.45;
    int b=5
    char C='A';
    cout<<"a="<<a<<","<<"b="<<b<<","<<"c="<<c <<endl;
输出结果为
   
a=3.45,b=5,c=A
   
如将上面的输出语句改为
    cout<<"a="<<setw(6)<<a<<endl<<"b="<<setw(6)<<b<<endl<<"c="<<setw(6)
    <<c<<endl;

    输出结果为
   
    a=3.45
        b=5
        C=A

   
在C++中将数据送到输出流称为“插入”(inserting)或“放到”(putting)。“<<”常称为“插入运算符”。

⑵用cin进行输入

    输人流是指从输入设备向内存流动的数据流。标准输入流cin是从键盘向内存流动的数据流。用">>"运算符从输入设备键盘取得数据送到输人流cin中,然后送到内存。 在C++中,这种输入操作称为“提取”(extracting)或“得到”(getting)。“>>”常称为“提取运算符”。

例5 cin与cout一起使用。

#include <iostream>
using namespace std;
int main( )
{cout<<"please enter your name and age:"<<endl;
char name[10];
int age;
cin>>name;
cin>>age;
cout<<"your name is "<<name<<endl;
cout<<"your age is "<< age<<endl;
return 0;
}

运行情况如下:
    please enter your name and age:
    Wang-ti/
    19/
    your name is Wang-Li
    your age is 19

    细心的读者可能已发现,程序中对变量的定义放在执行语句之后。C语言是不允许这样的,它要求声明部分必须在执行语句之前。而C++允许将变量的声明放在程序的任何位置(但必须在使用该变量之前)。这是C++对c限制的放宽。
    C++为流输入输出提供了格式控制,如:dec(用十进制形式),hex(用十六进制形 式),oct(用八进制形式),还可以控制实数的输出精度等。在本书第7章中有简单的介绍,也可以查阅有关书籍。
由上可知,C++的输入输出比c的输入输出简单易用。使用C++的程序员都喜欢用cin和cout语句进行输入输出。

(二)用const定义常变量

    在C语言中常用#define命令来定义符号常量,如
        #define P1 3.14159
   
实际上,只是在预编译时进行字符置换,把程序中出现的字符串PI全部置换为3.14159。在预编译之后,程序中不再有PI这个标识符。PI不是变量,没有类型,不占用存储单元,而且容易出错,如
    int a=l;b=2;
    #define P1 3.14159
    #define R a+b
    cout<<PI*R*R<<endl;
输出的并不是3.14159*(a+b)*(a+b),而是3.14159。a+b*a+b。程序因此而出错。
C++提供了用const定义常变量的方法,如: CONST float PI=3.4159;
   
定义了常变量PI,它具有变量的属性,有数据类型,占用存储单元,有地址,可以用指针指向它,只是在程序运行期间此变量的值是固定的,不能改变。它方便易用,避免了用#define定义符号常量时出现的缺点。因此,const问世后,已取代了用@define定义符号常量的作用。一般把程序中不允许改变值的变量定义为常变量。 const可以与指针结合使用,有指向常变量的指针、常指针、指向常变量的常指针等。

(三)函数原型声明

    在C语言程序中,如果函数调用的位置在函数定义之前,则应在函数调用之前对所调用的函数作声明,但如果所调用的函数是整型的,也可以不进行函数声明。对于函数声明的形式,C语言建议采用函数原型声明,如本章例1.3程序中对max函数声明那样。但这并不是强制的,在编译时是不严格的,例如用C语言编写例1.3程序时,可以不对max函数作声明,也可以采用简化的形式,如下面几种声明的形式都是合法的,都能通过编译。
    int max(int x,int y); /*max函数原型声明*/
   
int max();     /*不列出max函数的参数表*/
   
max();        /*max是整型函数,可以省略函数类型*/
   
在C++中,如果函数调用的位置在函数定义之前,则要求在函数调用之前必须对所调用的函数作函数原型声明,这不是建议性的,而是强制性的。这样做的目的是使编译系统对函数调用的合法性进行严格的检查,尽量保证程序的正确性。

函数声明的一般形式为
    函数类型函数名(参数表);

    参数表中一般包括参数类型和参数名,也可以只包括参数类型而不包括参数名,如下
面两种写法等价:

int max(int x,int y); //参数表中包括参数类型和参数名
int max(int,int);    //参数表中只包括参数类型、不包括参数名

在编译时只检查参数类型,而不检查参数名。

(四)函数的重载

    在前面的程序中用到了插入运算符“<<”和提取运算符“>>”。这两个运算符本来是c和C++位运算中的左移运算符和右移运算符,现在C++又把它作为输入输出运算符。即允许一个运算符用于不同场合,有不同的含义,这就叫运算符的“重载”(over loading),即重新赋予它新的含义,其实就是“一物多用”。
在C++中,函数也可以重载。用C语言编程时,有时会发现几个不同名的函数实现的是同一类的操作。例如要求从3个数中找出其中最大者,而这3个数的类型事先不确定,可以是整型、实型或长整数型。在写C语言程序时,需要分别设计出3个函数,其原型为
    int maxl(int a,int b,int c); (求3个整数中的最大者)
   
float max2(float a,float b,float c); (求3个实数中的最大者)
   
long max3(long a,long b,long c); (求3个长整数中的最大者)
   
C语言规定在同一作用域(例如同一文件模块中)中不能有同名的函数,因此3个函数的名字不相同。
C++允许在同一作用域中用同一函数名定义多个函数,这些函数的参数个数和参数类型不相同,这些同名的函数用来实现不同的功能。这就是函数的重载,即一个函数名多用。
对上面的问题可以编写如下的C++程序。

例6 求3个数中最大的数(分别考虑整数、实数、长整数的情况)。

#include <iostream>
using namespace std;
int max(int a,int b,int c)     //求3个整数中的最大者
 
{ if (b>a) a=b;
   if (c>a) a=c;
   return a;
  }
float max(float a,float b, float c) //求3个实数中的最大者
   
{ if (b>a) a=b;
     if (c>a) a=c;
     return a;
    }
long max(long a,long b,long c) //求3个长整数中的最大者
  
{ if (b>a) a=b;
    if (c>a) a=c;
    return a;
   }

int main( )
 { int a,b,c; float d,e,f; long g,h,i;
   cin>>a>>b>>c;
   cin>>d>>e>>f;
   cin>>g>>h>>i;
   int m;
   m=max(a,b,c); //函数值为整型
   
cout <<"max_i="<<m<<endl;
   float n;
   n=max(d,e,f); //函数值为实型
  
cout<<"max_f="<<n<<endl;
   long int p;
   p=max(g,h,i); //函数值为长整型
   
cout<<"max_l="<<p<<endl;
   return 0;
  }

运行情况如下:
   
8 5 6/ (输人3个整数给变量a,b,c)
    56.9 90.765 43.1/ (输入3个实数给变量d,c,f)
    67543 -567 78123/ (输入3个长整数绐变量g,h,i)
    max_i=8 (输出3个整数的最大值)
    max_f=90.765 (输出3个实数的最大值)
    max_l=78123 (输出3个长整数的最大值)

    main函数3次调用max函数,每次实参的类型不同。系统会根据实参的类型找到与匹配的函数,然后调用该函数。上例3个max函数的参数个数相同而类型不同。参数个数也可以不同。

例7 用一个函数求2个整数或3个整数中的最大者。

#include <iostream>
using namespace std;
int max(int a,int b,int c) //求3个整数中的最大者
 
{ if (b>a) a=b;
   if (c>a) a=c;
   return a;
  }
int max(int a, int b) //求两个整数中的最大者
{  if (a>b) return a;
   else return b;
}
int main( )
{  int a=7,b=-4,c=9;
   cout<<max(a,b,c)<<endl; //输出3个整数中的最大者
   
cout<<max(a,b)<<endl; //输出两个整数中的最大者
   
return 0;
}

运行情况如下:
   
9 (3个整数中的最大者)
    7 (前两个整数中的最大者)

(五)函数模板

   函数的重载可以实现一个函数名多用,将实现相同的或类似功能的函数用同一个函数名来定义。这样可以使编程者在调用同类函数时感到含义清楚,方法简单。但是在程序中仍然要分别定义每一个函数,如例1.6的程序中三个max函数的函数体是完全相同的,只是形参的类型不同,也要分别定义。有些读者自然会想到,对此能否再简化呢?
    为了解决这个问题,C++提供了函数模板(function template)。所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只须在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。

例8 将例6中的程序改为通过函数模板来实现。

#include<iostream>
using namespace std;
template<typename T>; //模板声明,其中T为类型参数
T max(T a,T b,T c)   //定义一个通用函数,用T作虚拟的类型名
{ if(b>a)a;b:
  if(c>a)a:c;
  return a:
}
int main()
{ int i1=8,i2=5,i3=6,i;
  double dl=56.9,d2=90.765,d3=43.1,d;
  long g1=67843,g2=-456,g3=78123,g;
  i=max(i1,i2,i3);     //调用模板函数,此时T被int取代
  
d=max(d1,d2,d3);   //调用模板函数,此时T被double取代
  
g=max(8l,S2,83);   //调用模板函数,此时T被long取代
  
cout <<"i_max="<<i <<endl;
  cout<<"f_max="<< f << endl;
  cout<< "g_max="<<g <<endl;
  return ();}

    运行结果与例6相同。为了节省篇幅,数据不用cin语句输入,而在变量定义时初始化。程序第3-8行是定义模板。定义函数模板的一般形式为
        template<typename T> 或template<class T>
通用函数定义 通用函数定义。
   
   
class和typename的作用相同,都是表示“类型名”,二者可以互换。以前的C++程序员都用class。typename是不久前才被加到标准C++中的,因为用class容易与C++中的类混淆。而用typename其含义就很清楚,肯定是类型名(而不是类名)。
    可能对模板中通用函数的表示方法不习惯,其实在建立函数模板时,只要将例6程序中定义的第一个函数首部的int改为T即可。即用虚拟的类型名T代替具体的数据类型。在对程序进行编译时,遇到第13行调用函数max(i1,i2,i3),编译系统会将函数名max与模板max相匹配,将实参的类型取代函数模板中的虚拟类型T。此时相当于已定义了一个函数:
        int max(int a,int b,int c)
        { if(b>a) a=b;
          if(c>a) a=c;
          return a;
        }
然后调用它。后面两行(14,15行)的情况类似。 类型参数可以不只一个,可根据需要确定个数。如
    template<class T1,typename T2>
   
可以看到,用函数模板比函数重载更方便,程序更简洁。但应注意它只适用于函数的参数个数相同而类型不同,且函数体相同的情况,如果参数的个数不同,则不能用函数模板.

原文:http://210.44.195.12/cgyy/text/HTML/text/02.htm