首页 C++教程1[1]

C++教程1[1]

举报
开通vip

C++教程1[1]c++参考教程  C++语言概述 C++语言是一种应用较广的面向对象的程序设计语言,使用它可以实现面向对象的程序设计。面向对象的设计与面向过程的设计是有很大区别的,面向对象的程序设计是在面向过程的程序设计的基础上一个质的飞跃。要学会面向对象的程序设计,首先要学会一种面向对象的语言,即要学会用VC编程,就要先有C++的基础,而学习C++语言首先要认识它面向对象的特性和实现面向对象的方法。   C++是一种面向对象的程序设计语言   当你首次学习C++时,总会碰到一些在C语言从未见过的概念,如:类、对象、抽象、封装、继...

C++教程1[1]
c++参考教程  C++语言概述 C++语言是一种应用较广的面向对象的程序 设计 领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计 语言,使用它可以实现面向对象的程序设计。面向对象的设计与面向过程的设计是有很大区别的,面向对象的程序设计是在面向过程的程序设计的基础上一个质的飞跃。要学会面向对象的程序设计,首先要学会一种面向对象的语言,即要学会用VC编程,就要先有C++的基础,而学习C++语言首先要认识它面向对象的特性和实现面向对象的方法。   C++是一种面向对象的程序设计语言   当你首次学习C++时,总会碰到一些在C语言从未见过的概念,如:类、对象、抽象、封装、继承、多态性、虚函数等等。这些概念是C++所具有,下面简单的介绍一下C++对面向对象程序设计方法的支持和实现。   1、C++支持数据封装   支持数据封装就是支持数据抽象。在C++中,类是支持数据封装的工具,对象则是数据封装的实现。面向过程的程序设计方法与面向对象的程序设计方法在对待数据和函数关系上是不同的,在面向对象的程序设计中,将数据和对该数据进行合法操作的函数封装在一起作为一个类的定义,数据将被隐藏在封装体中,该封装体通过操作接口与外界交换信息。对象被说明具有一个给定类的变量,类类似于C语言中的结构,在C语言中可以定义结构,但这种结构中包含数据,而不包含函数。C++中的类是数据和函数的封装体。在C++中,结构可作为一种特殊的类,它虽然可以包含函数,但是它没有私有或保护的成员。   2、C++类中包含私有、公有和保护成员   C++类中可定义三种不同访控制权限的成员。一种是私有(Private)成员,只有在类中说明的函数才能访问该类的私有成员,而在该类外的函数不可以访问私有成员;另一种是公有(Public)成员,类外面也可访问公有成员,成为该类的接口;还有一种是保护(Protected)成员,这种成员只有该类的派生类可以访问,其余的在这个类外不能访问。   3、C++中通过发关消息来处理对象   C++中是通过向对象发关消息来处理对象的,每个对象根据所接收到的消息的性质来决定需要采取的行动,以响应这个消息。响应这些消息是一系列的方法,方法是在类定义中使用函数来定义的,使用一种类似于函数调用的机制把消息发送到一个对象上。   4、C++中允许友元破坏封装性   类中的私有成员一般是不允许该类外面的任何函数访问的,但是友元便可打破这条禁令,它可以访问该类的私有成员(包含数据成员和成员函数)。友元可以是在类外定义的函数,也可以是在类外定义的整个类,前者称友元函数,后者称为友元类。友元打破了类的封装性,它是C++另一个面向对象的重要牲。   5、C++允许函数名和运算符重载   C++支持多态性,C++允许一个相同的标识符或运算符代表多个不同实现的函数,这就称标识符或运算符的重载,用户可以根据需要定义标识符重载或运算符重载。   6、C++支持继承性   C++中可以允许单继承和多继承。一个类可以根据需要生成派生类。派生类继承了基类的所有方法,另外派生类自身还可以定义所需要的不包含在父类中的新方法。一个子类的每个对象包含有从父类那里继承来的数据成员以及自己所特有的数据成员。   7、C++支持动态联编   C++中可以定义虚函数,通过定义虚函数来支持动态联编。   以上是所讲的是C++对面向对象程序设计中的一些主要特征的支持。   C++的词法及词法规则   1、C++的字符集   字符是一些可以区分的最小符号。C++的字符集由大小写英文字母(a-z和A-Z)、数据字符(0-9)、特殊字符(空格,!,#,%,^,&,*,_,<,>,?,\,,)组成。   2、单词及词法规则   单词又称词法记号,它是由若干个字符组成的具有一定意义的最小词法单元。C++共有6种单词,分别是:标识符、关键字、运算符、分隔符、常量、注释符,在编码时要特别注意这些单词的词法规则。要注意的是C++中的空白符:C++中经常使用空白符,实际上,空白符不是一个字符,它是空格符、换行符和水平制表符的统称。注意,空白符不等于空格符,只是空白符包含空格符。还有一个空字符,要把它与空白符分开。空字符是指ASCII码值为0的那个字符。空字符在C++中有特殊用途,用它来作为字符串的结束符。存放在内存中的字符串常量都在最后有一个结束符,即用空字符,它用转义序列方法表示为'\0'。   C++程序结构的组成   C++程序结构的基本组成部分   1 预处理命令,C++提供了三类预处理命令:宏定义命令、文件包含命令、条件编译命令。   2 输入输出,C++程序中总是少不了输入和输出的语句,实现与程序内部的信息交流。特别是屏幕输出的功能,几乎每个程序都要用到,使用它把计算机的结果显示在屏幕上。   3 函数,C++的程序是由若干个文件组成的,每个文件又是由若干个函数组成,因此,可以认为C++的程序就是函数串,即由若干个函数组成,函数与函数之间是相对的,并且是并行的,函数之间可以调用。在组成一个程序的若干个函中,必须有一个main()。   4 语句,语句是组成程序的基本单元。函数是由若干条语句组成的。但是,空函数是没有语句的。语句是由单词组成,单词间用空格符分隔,C++程序中的语句又是以以分号结束。语句除了有表达式语句和空语句之外,还有复合语句、分支语句、循环语句和转向语句等若干类。   5 变量,多数程序都需要说明和使用变量。广义讲,对象包含了变量,即将变量也称为一种对象,狭义讲,将对象看作是类的实例,对象是指某个类的对象。   6 其他,除了以上讲述的5个部分以外,还有其他组成部分。例如,符号常量和注释信息也是程序的一部分。C++中都尽量把常量定义为符号常量,在C++的程序中出现的是符号常量,该符号常量代表着某个确定的常量值。   C++程序的书写格式   在编程时应该注意C++的书写格式,基本原则是:一行一般写一条语句。短语句可以一行写多个。长语句可以一条写多行。分行原则是不能将一个单词分开。用双引号引用的一个字符串也最好不分开,如果一定要分开,有的编译系统要求在行尾加续行符(“\”)   C++程序的实现   C++源程序的实现与其他高级语言源程序实现的原理是一样的。一般都要经过编辑、编译、运行。其中最要的是编译过程,C++是以编译方式实现的高级语言。C++程序的实现,必须要使用某种C++语言的编译器对程序进行编译。编译器的功能是将程序的源代码转换成为机器代码的形式,称为目标代码;然后,再使目标代码进行连接,生成可执行文件。该过程可分为三个子过程:预处理过程、编译过程(词法分析、语法分析、符号表、错误处理程序、生成目标代码)、连接过程。 C++常类型(const) 常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。因此,定义或说明常类型时必须进行初始化。   一般常量和对象常量   1. 一般常量   一般常量是指简单类型的常量。这种常量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后。如:   int const x=2;   或   const int x=2;   定义或说明一个常数组可采用如下格式:   <类型说明符> const <数组名>[<大小>]…   或者   const <类型说明符> <数组名>[<大小>]…   例如:   int const a[5]={1, 2, 3, 4, 5};   2. 常对象   常对象是指对象常量,定义格式如下:   <类名> const <对象名>   或者   const <类名> <对象名>   定义常对象时,同样要进行初始化,并且该对象不能再被更新,修饰符const可以放在类名后面,也可以放在类名前面。   常指针和常引用   1. 常指针   使用const修饰指针时,由于const的位置不同,而含意不同。下面举两个例子,说明它们的区别。   下面定义的一个指向字符串的常量指针:   char * const prt1 = stringprt1;   其中,ptr1是一个常量指针。因此,下面赋值是非法的。   ptr1 = stringprt2;   而下面的赋值是合法的:   *ptr1 = "m";   因为指针ptr1所指向的变量是可以更新的,不可更新的是常量指针ptr1所指的方向(别的字符串)。   下面定义了一个指向字符串常量的指针:   const * ptr2 = stringprt1;   其中,ptr2是一个指向字符串常量的指针。ptr2所指向的字符串不能更新的,而ptr2是可以更新的。因此,   *ptr2 = "x";   是非法的,而:   ptr2 = stringptr2;   是合法的。   所以,在使用const修饰指针时,应该注意const的位置。定义一个指向字符串的指针常量和定义一个指向字符串常量的指针时,const修饰符的位置不同,前者const放在*和指针名之间,后者const放在类型说明符前。   2. 常引用   使用const修饰符也可以说明引用,被说明的引用为常引用,该引用所引用的对象不能被更新。其定义格式如下:   const <类型说明符> & <引用名>   例如:   const double & v;   在实际应用中,常指针和常引用往往用来作函数的形参,这样的参数称为常参数。   在C++面向对象的程序设计中,指针和引用使用得较多,其中使用const修饰的常指针和常引用用得更多。使用常参数则表明该函数不会更新某个参数所指向或所引用的对象,这样,在参数传递过程中就不需要执行拷贝初始化构造函数,这将会改善程序的运行效率。   下面举一例子说明常指针作函数参数的作法。 #include const int N = 6; void print(const int *p, int n); void main() { int array[N]; for (int i=0; i cin>>array[i]; print(array, N); } void print(const int *p, int n) { cout<<"{"<<*p; for (int i=1; i cout<<","<<*(p+i); cout<<"}"< }    常成员函数   使用const关键字进行说明的成员函数,称为常成员函数。只有常成员函数才有资格操作常量或常对象,没有使用const关键字说明的成员函数不能用来操作常对象。常成员函数说明格式如下:   <类型说明符> <函数名> (<参数表>) const; 其中,const是加在函数说明后面的类型修饰符,它是函数类型的一个组成部分,因此,在函数实现部分也要带const关键字。下面举一例子说明常成员函数的特征。 #include class R { public: R(int r1, int r2) { R1=r1; R2=r2; } void print(); void print() const; private: int R1, R2; }; void R::print() { cout< } void R::print() const { cout< } void main() { R a(5, 4); a.print(); const R b(20, 52); b.print(); }    该例子的输出结果为:   5,4    20;52   该程序的类声明了两个成员函数,其类型是不同的(其实就是重载成员函数)。有带const修饰符的成员函数处理const常量,这也体现出函数重载的特点。   常数据成员   类型修饰符const不仅可以说明成员函数,也可以说明数据成员。   由于const类型对象必须被初始化,并且不能更新,因此,在类中说明了const数据成员时,只能通过成员初始化列表的方式来生成构造函数对数据成员初始化。   下面通过一个例子讲述使用成员初始化列表来生成构造函数。 #include class A { public: A(int i); void print(); const int &r; private: const int a; static const int b; }; const int A::b=10; A::A(int i):a(i), r(a) { } void A::print() { cout< } void main() { A a1(100), a2(0); a1.print(); a2.print(); }    该程序的运行结果为:   100:10:100     0:10:0   在该程序中,说明了如下三个常类型数据成员:   const int & r;   const int a;   static const int b;   其中,r是常int型引用,a是常int型变量,b是静态常int型变量。   程序中对静态数据成员b进行初始化。   值得注意的是构造函数的格式如下所示:   A(int i):a(i),r(a)    {    }   其中,冒号后边是一个数据成员初始化列表,它包含两个初始化项,用逗号进行了分隔,因为数据成员a和r都是常类型的,需要采用初始化格式。 浅谈C++函数的参数 函数参数的求值顺序   当一个函数带有多个参数时,C++语言没有规定在函数调用时实参的求值顺序。而编译器根据对代码进行优化的需要自行规定对实参的求值顺序。有的编译器规定自左至右,有的编译器规定自右至左,这种对求值顺序的不同规定,对一般参数来讲没有影响。但是,如果实参表达式中带有副作用的运算符时,就有可能产生由于求值顺序不同而造成了二义性。例如:int z = add_int(++x, x+y);,这样,在不同的编译器就有可能生产不同的结果。   设置参数的默认值   在C++语言中,允许在函数的说明或定义时给一个或多个参数指定默认值。但是,要求在一个指定了默认值的参数的右边,不能出现没有指定默认值的参数。例如:    int add_int(int x, int 10);   在上述对函数add_int()的说明中,对该函数的最右边的一个参数指定了默认值。   在函数调用时,编译器按从左至右的顺序将实参与形参结合,当实参的数目不足时,编译器将按同样的顺序用说明中或定义中的默认值来补足所缺少的实参。例如,如有下列的函数调用表达式:    add_int(15)   它将与下列调用表达式:    add_int(15, 10)   是等价的。   在给某个参数指定默认值是,不仅可以是一个数值,而且还可以是任意复杂的表达式。   使用数组作函数参数    数组作函数参数可以分为如下三种情况:(这三种情况的结果相同,只是所采用的调用机制不同)   1. 形参和实参都用数组   调用函数的实参用数组名,被调用函数的形参用数组,这种调用的机制是形参和实参共用内存中的同一个数组。因此,在被调用函数中改变了数组中某个无素的值,对调用函数该数组的该元素值也被改变,因为它们是共用同一个数组。   2. 形参和实参都用对应数组的指针   在C++中,数组名被规定为是一个指针,该指针便是指向该数组的首元素的指针,国为它的值是该数组首元素的地址值,因此,数组名是一个常量指针。   实际中,形参和实参一个用指针,另一个用数组也是可以的。在使用指针时可以用数组名,也可以用另外定义的指向数组的指针。   3. 实参用数组名形参用引用   如何对数组类型使用引用方式,这里先做如下说明:先用类型定义语句定义一个int型的数组类型,如下所示:   typedef int array[8];   然后,使用array来定义数组和引用。   示例: #include typedef int array[8]; int a[8] = {1, 3, 5, 7, 9, 11, 13}; void fun(array &b, int n) { for(int i=0; i b[7]+=b[i]; } void main() { int m=8; fun(a, m); cout< }    该程序中,在fun()函数中,使用了引用作形参,调用时所对应的实参应该是一个数组名,这里的引用是给数组起个别名。在fun()函数中对数组b的操作,就相当于b所引用数组a的操作。在C++中,常用这种调用方式。 C++语法之函数重载 所谓函数重载是指同一个函数名可以对应着多个函数的实现。例如,可以给函数名add()定义多个函数实现,该函数的功能是求和,即求两个操作数的和。其中,一个函数实现是求两个int型数之和,另一个实现是求两个浮点型数之和,再一个实现是求两个复数的和。每种实现对应着一个函数体,这些函数的名字相同,但是函数的参数的类型不同。这就是函数重载的概念。函数重载在类和对象的应用尤其重要。   函数重载要求编译器能够唯一地确定调用一个函数时应执行哪个函数代码,即采用哪个函数实现。确定函数实现时,要求从函数参数的个数和类型上来区分。这就是说,进行函数重载时,要求同名函数在参数个数上不同,或者参数类型上不同。否则,将无法实现重载。   参数类型上不同的重载函数   下面举一个在参数类型不同的重载函数的例子: #include int add(int, int); double add(double, double); void main() { cout< cout< } int add(int x, int y) { return x+y; } double add(double a, double b) { return a+b; }    该程序中,main()函数中调用相同名字add的两个函数,前边一个add()函数对应的是两个int型数求和的函数实现,而后边一个add()函数对应的是两个double型数求和的函数实现。这便是函数的重载。   以上程序输出结果为:   15   15.5   参数个数上不同的重载函数   下面举一个在参数个数上不相同的重载函数的例子: #include int min(int a, int b); int min(int a, int b, int c); int min(int a, int b, int c, int d); void main() { cout< cout< } int min(int a, int b) { return a } int min(int a, int b, int c) { int t = min(a, b); return min(t,c); } int min(int a, int b, int c, int d) { int t1 = min(a, b); int t2 = min(c, d); return min(t1, t2); }    该程序中出现了函数重载,函数名min对应有三个不同的实现,函数的区分依据参数个数不同,这里的三个函数实现中,参数个数分别为2,3和4,在调用函数时根据实参的个数来选取不同的函数实现。   函数重载在类和对象应用比较多,尤其是在类的多态性中。在以后我们将碰到更多的在类型不同的函数重载,尤其是在结合类的继承性和指针类型的不同,而这些都是我们以后用VC编程中经常要用到的。 C++子对象和堆对象 子对象   当一个类的成员是某一个类的对象时,该对象就为子对象。子对象实际就是对象成员。如: class A {   public:    …   private:    … }; class B   {    public:     …    private:     A a;     …   };    其中,B类中成员a就是子对象,它是A类的对象作为B类的成员。   在类中出现了子对象或称对象成员时,该类的构造函数要包含对子对象的初始化,通常采用成员初始化表的方法来初始化子对象。在成员初始化表中包含对子对象的初始化和对类中其他成员的初始化。下面举一例子说明成员初始化的构造。 #include class A { public: A(int i, int j) { A1=i; A2=j; } void print() { cout< private: int A1, A2; }; class B { public: B(int i, int j, int k):a(i, j), b(k) { } void print(); private: A a; file://子对象 int b; }; void B::print() { a.print(); cout< } void main() { B b(6, 7, 8); b.print(); }    该程序的输出结果为:   6,7    8   其中,a(i, j), b(k)是成员初始化表,它有二项,前一项是给子对象a初始化,其格式如下:    <子对象名> (<参数表>)   后一项是给类B的数据成员b初始化。这一项也可以写在构造函数的函数体内,使用赋值表达式语句    b = k;   给类B的数据成员初始化。   堆对象   所谓堆对象是指在程序运行过程中根据需要随时可以建立或删除的对象。这种堆对象被创建在内存一些空闲的存储单元中,这些存储单元被称为堆。它们可以被创建的堆对象占有,也可以通过删除堆对象而获得释放。   创建或删除堆对象时,需要如下两个运算符:    new    delete   这两个运算符又称为动态分配内存空间运算符。new相当于C语言中malloc()函数,而delete相当于C语言中free()函数。   1. 运算符new的用法   该运算符的功能是用来创建堆对象,或者说,它是用来动态地创建对象。   new运算符使用格式如下:   new <类型说明符> (<初始值列表>)   它表明在堆中建立一个由<类型说明符>给定的类型的对象,并且由括号中的<初始值列表>给出被创建对象的初始值。如果省去括号和括号中的初始值,则被创建的对象选用缺省值。   使用new运算符创建对象时,它可以根据其参数来选择适当的构造函数,它不用sizeof来计算对象所占的字节数,而可以计算其大小。   new运算符返回一个指针,指针类型将与new所分配对象相匹配,如果不匹配可以通过强制类型的方法,否则将出现编译错。   如果new运算符不能分配到所需要的内存,它将返回0,这时的指针为空指针。   运算符new也可以用来创建数组类型的对象,即对象数组。其格式如下:    new <类名> [<算术表达式>]   其中,<算术表达式>的值为所创建的对象数组的大小。如:    A *ptr;     ptr = new A[5];   new还可用来创建一般类型的数组。如:    int *p;     p = new int[10];   使用new[]创建的对象数组或一般数组时,不能为该数组指定初始值,其初始值为缺省值。   2. 运算符delete的用法   该运算符的功能是用来删除使用new创建的对象或一般类型的指针。其格式如下:    delete <指针名>   例如:    A *ptr;     ptr = new A(5, 6);     delete ptr;   运算符delete也可用来删除使用new创建对象数组,其使用格式如下:    delete[] <指针名>   同样,delete也可以删除由new创建的一般类型的数组。如:    int *p;     p = new int[10];     delete[] p;   使用运算符delete时,应注意如下几点:    (1) 它必须使用于由运算符new返回的指针;    (2) 该运算符也适用于空指针(即其值为0的指针);    (3) 指针名前只用一对方括号符,并且不管所删除数组的维数,忽略方括号内的任何数字。   下面举一例子说明new运算符和delete运算符的使用方法。 #include class AA { public: AA(int i, int j) { A=i; B=j; cout<<"构造函数.\n"; } ~AA() { cout<<"析构函数.\n"; } void print(); private: int A, B; }; void AA::print() { cout< } void main() { AA *a1, *a2; a1 = new AA(1, 2); a2 = new AA(5, 6); a1->print(); a2->print(); delete a1; delete a2; }     该程序的输出结果为:     构造函数.      构造函数.      1, 2      5, 6      构造函数.      构造函数.   从程序中可以看到:用new创建对象时,要调用构造函数,用delete删除对象时,要调用析构函数。如果创建或删除的时对象数组,对象数组有多少,就调用多少次构造函数或构造函数。   在实际应用中,经常对于new运算符返回的指针进行检验,看是否分配了有效的内存空间。结合本例给出检验方法如下:   if (!a1)     {      cout<<"Heap erroe!\n";      exit(1);     }   下面再举一个使用new和delete运算符对一般指针和数组的例子。 #include #include void fun() { int *p; if (p = new int) { *p = 5; cout<<*p< delete p; } else cout<<"Heap error!\n"; } void main() { fun(); int *pa; pa = new int[5]; if (!pa) { cout<<"Heap error!\n"; exit(1); } for (int i=0; i<5; i++) pa[i] = i+1; for (i=0; i<5; i++) cout<(<派生类构造函数总参数表>):<基类构造函数>(参数表1),<子对象名>(<参数表2>)    {    <派生类中数据成员初始化>    };   派生类构造函数的调用顺序如下:    · 基类的构造函数    · 子对象类的构造函数(如果有的话)    · 派生类构造函数   在前面的例子中,B::B(int i, int j, int k):A(i), bb(j), bbb(k)就是派生类构造函数的定义,下面再举一个构造派生类构造函数的例子。 #include class A { public: A() { a=0; cout<<"类A的缺省构造函数.\n"; } A(int i) { a=i; cout<<"类A的构造函数.\n"; } ~A() { cout<<"类A的析构函数.\n"; } void Print() const { cout< int Geta() { reutrn a; } private: int a; } class B : public A { public: B() { b=0; cout<<"类B的缺省构造函数.\n"; } B(int i, int j, int k); ~B() { cout<<"类B的析构函数.\n"; } void Print(); private: int b; A aa; } B::B(int i, int j, int k):A(i), aa(j) { b=k; cout<<"类B的构造函数.\n"; } void B::Print() { A::Print(); cout< } void main() { B bb[2]; bb[0] = B(1, 2, 5); bb[1] = B(3, 4, 7); for(int i=0; i<2; i++) bb[i].Print(); }    2. 构造函数   当对象被删除时,派生类的析构函数被执行。由于析构函数也不能被继承,因此在执行派生类的析构函数时,基类的析构函数也将被调用。执行顺序是先执行派生类的构造函数,再执行基类的析构函数,其顺序与执行构造函数时的顺序正好相反。这一点从前面讲过的例子可以看出,请读者自行分析。   3. 派生类构造函数使用中应注意的问题   (1) 派生类构造函数的定义中可以省略对基类构造函数的调用,其条件是在基类中必须有缺省的构造函数或者根本没有定义构造函数。当然,基类中没有定义构造函数,派生类根本不必负责调用基类的析构函数。   (2) 当基类的构造函数使用一个或多个参数时,则派生类必须定义构造函数,提供将参数传递给基类构造函数途径。在有的情况下,派生类构造函数的函数体可能为空,仅起到参数传递作用。如本讲第一个例子就属此种情况。   子类型化和类型适应   1. 子类型化   子类型的概念涉及到行为共享,它与继承有着密切关系。   有一个特定的类型S,当且仅当它至少提供了类型T的行为,由称类型S是类型T的子类型。子类型是类型之间的一般和特殊的关系。   在继承中,公有继承可以实现子类型。例如: class A { public: void Print() const { cout<<"A::print() called.\n"; } }; class B : public A { public: void f() {} };    类B继承了类A,并且是公有继承方式。因此,可以说类B是类A的一个子类型。类A还可以有其他的子类型。类B是类A的子类型,类B具备类A中的操作,或者说类A中的操作可被用于操作类B的对象。   子类型关系是不可逆的。这就是说,已知B是A的子类型,而认为A也是B的子类型是错误的,或者说,子类型关系是不对称不。   因此,可以说公有继承可以实现子类型化。   2. 类型适应   类型适应是指两种类型之间的关系。例如,B类型适应A类型是指B类型的对象能够用于A类型的对象所能使用的场合。   前面讲过的派生类的对象可以用于基类对象所能使用的场合,我们说派生类适应于基类。   同样道理,派生类对象的指针和引用也适应于基类对象的指针和引用。   子类型化与类型适应是致的。A类型是B类型的子类型,那么A类型必将适应于B类型。   子类型的重要性就在于减轻程序人员编写程序代码的负担。因为一个函数可以用于某类型的对象,则它也可以用于该类型的各个子类型的对象,这样就不必为处理这些子类型的对象去重载该函数。 C++多继承 多继承可以看作是单继承的扩展。所谓多继承是指派生类具有多个基类,派生类与每个基类之间的关系仍可看作是一个单继承。   多继承下派生类的定义格式如下:   class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…     {      <派生类类体>     };   其中,<继承方式1>,<继承方式2>,…是三种继承方式:public、private、protected之一。例如: class A { … }; class B { … }; class C : public A, public, B { … }; 其中,派生类C具有两个基类(类A和类B),因此,类C是多继承的。按照继承的规定,派生类C的成员包含了基类B中成员以及该类本身的成员。   多继承的构造函数   在多继承的情况下,派生类的构造函数格式如下:   <派生类名>(<总参数表>):<基类名1>(<参数表1>),<基类名2>(<参数表2>),…     <子对象名>(<参数表n+1>),…      {       <派生类构造函数体>      }   其中,<总参数表>中各个参数包含了其后的各个分参数表。   多继承下派生类的构造函数与单继承下派生类构造函数相似,它必须同时负责该派生类所有基类构造函数的调用。同时,派生类的参数个数必须包含完成所有基类初始化所需的参数个数。   派生类构造函数执行顺序是先执行所胡基类的构造函数,再执行派生类本身构造函数,处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化列表的各项顺序无关。也就是说,执行基类构造函数的顺序取决于定义派生类时基类的顺序。可见,派生类构造函数的成员初始化列表中各项顺序可以任意地排列。    下面通过一个例子来说明派生类构造函数的构成及其执行顺序。 #include class B1 { public: B1(int i) { b1 = i; cout<<"构造函数 B1."< } void print() { cout< private: int b1; }; class B2 { public: B2(int i) { b2 = i; cout<<"构造函数 B2."< } void print() { cout< private: int b2; }; class B3 { public: B3(int i) { b3 = i; cout<<"构造函数 B3."< } int getb3() { return b3; } private: int b3; }; class A : public B2, public B1 { public: A(int i, int j, int k, int l):B1(i), B2(j), bb(k) { a = l; cout<<"构造函数 A."< } void print() { B1::print(); B2::print(); cout< } private: int a; B3 bb; }; void main() { A aa(1, 2, 3, 4); aa.print(); }    该程序的输出结果为:    构造函数 B2.2    构造函数 B1.1    构造函数 B3.3    构造函数 A.4    1    2    4, 3   在该程序中,作用域运算符::用于解决作用域冲突的问题。在派生类A中的print()函数的定义中,使用了B1::print;和B2::print();语句分别指明调用哪一个类中的print()函数,这种用法应该学会。 C++ 对象与数组 对象数组是指数组元素为对象的数组。该数组中若干个元素必须是同一个类的若干个对象。对象数组的定义、赋值和引用与普通数组一样,只是数组的元素与普通数组不同,它是同类的若干个对象。   1. 对象数组的定义   对象数组定义格式如下:    <类名><数组名>[<大小>]...   其中,<类名>指出该数组元素是属于该类的对象,方括号内的<大小>给出某一维的元素个数。一维对象数组只有一个方括号,二维对象数组要有两个方括号,等等,例如:    DATE dates[7];   表明dates是一维对象数组名,该数组有7个元素,每个元素都是类DATE的对象。   2. 对象数组的赋值   对象数组可以被赋初值,也可以被赋值。例如: class DATE {   public:    DATE(int m, int d, int y);    void printf();   private:    int month, day, year; };    下面是定义对象数组并赋初值和赋值:    DATE dates[4]={ DATE(7, 7, 2001), DATE(7, 8, 2001), DATE(7, 9, 2001), DATE(7, 10, 2001) }   或者    dates[0] = DATE(7, 7, 2001);     dates[1] = DATE(7, 8, 2001);     dates[2] = DATE(7, 9, 2001);     dates[3] = DATE(7, 10, 2001); 指向数组的指针和指针数组   指向数组的指针和指针数组是两个完全不同的概念,现放在一起介绍是中为两者在定义格式相似,千万不要把它们搞混了。   1. 指向数组的指针   指向一般数组的指针定义格式如下:    <类型说明符>(*<指针名>)[<大小>]...   其中,用来说明指针的 * 要与<指针名>括在一起。后面用一个方括号表示该指针指向一维数组,后面用二个方括号表示该指针指向二维数组。<类型说明符>用来说明指针所指向的数组的元素的类型。例如:    int (*P)[3];   P是一个指向一维数组的指针,该数组有3个int型元素。   而指向对象数组的指针,则把<类型说明符>改为<类名>即可:    <类名>(*<指针名>)[<大小>]...   指向数组的指针的主要应用思想是:将数组的首地址(二维数组的某个行地址)赋给指针,然后通过循环(for)改变指针指向的地址,从而动态的访问数组中各个元素。   2. 指针数组   所谓指针数组指的是数组元素为指针的那类数组。一个数组的元素可以是指向同一类型的一般指针,也可以是指向同一类类型的对象。   一般指针数组的定义格式如下:    <类型名>*<数组名>[<大小>]...   其中,*加在<数组名>前面表示该数组为指针数组。[<大小>]表示某一维的大小,即该维的元素个数,…表示可以是多维指针数组,每一个[<大小>]表示一维。例如:    int * pa[3];     char * pc[2][5];   在C++编程中,经常使用char型的指针数组用来存放若干个字符串。下面是一个一维指针数组的例子。 #include #include const int N = 5; void main() { char *strings[N]; file://定义一个一维指针数组strings char str[80]; cout<<"At each prompt, enter a string:\n"; for (int i=0; i { cout<<"Enter a string #"< cin.getline(str, sizeof(str)); strings[i] = new char[strlen(str) + 1]; strcpy(strings[i], str); } cout< for (i=0; i cout<<"String #"< }    对象指针数组的定义如下:   对象指针数组是指该数组的元素是指向对象的指针,它要求所有数组元素都是指向同一个类类型的对象的指针。格式如下:   <类名>*<数组名>[<大小>]...   它与前面讲过的一般的指针数组所不同的地方仅在于该数组一定是指向对象的指针。即指向对象的指针用来作该数组的元素。下面通过一个例子看一下对象指针数组的用法。 #include class A { public: A(int i=0, int j=0) { a=i; b=j; } void print(); private: int a, b; }; void A::print() { cout< } void main() { A a1(7, 8), a2, a3(5, 7); A *b[3] = { &a3, &a2, &a1 }; for (int i=0; i<3; i++) b[i]->print(); } C++ 类的静态成员(static) 静态成员的提出是为了解决数据共享的问题。实现共享有许多方法,如:设置全局性的变量或对象是一种方法。但是,全局变量或对象是有局限性的。这一章里,我们主要讲述类的静态成员来实现数据的共享。   静态数据成员   在类中,静态成员可以实现多个对象之间的
本文档为【C++教程1[1]】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_169634
暂无简介~
格式:doc
大小:92KB
软件:Word
页数:0
分类:其他高等教育
上传时间:2014-03-10
浏览量:14