知识屋:更实用的电脑技术知识网站
所在位置:首页 > 教育

C++派生类的语法

发表时间:2022-03-25来源:网络

一.派生类的概念

1.为什么要使用继承

继承性也是程序设计中的一个非常有用的、有力的特性, 它可以让程序员在既有类的基础上,通过增加少量代码或修改少量代码的方法得到新的类, 从而较好地解决了代码重用的问题。

2.派生类的说明

在类名 employee 的冒号之后, 跟着关键字 public 与类名 person,这就意味着类 employee 将继承类 person 的全部特性。
关键字 public 指出派生的方式,告诉编译程序派生类employee从基类 person 公有派生。

// 定义一个基类( person 类) class person { private : char name [10] ; int age; char sex; public: // … } ; // 定义一个派生类 class employeepublic person { char department[20] ; float salary; public: // … } ;

声明一个派生类的一般格式为:

class 派生类名∶派生方式 基类名 { // 派生类新增的数据成员和成员函数 } ;

派生方式”可以是关键字 private 或 public。如果使用了 private, 则称派生类从基类私有派生; 如果使用了 public,则称派生类从基类公有派生。派生方式可以缺省, 这时派生方式默认为private ,即私有派生。

1. 公有派生

class employeepublic person { // … };

2. 私有派生

class employeeprivate person { // … } ;

这两种派生方式的特点如下:

无论哪种派生方式, 基类中的私有成员既不允许外部函数访问, 也不允许派生类中的成员函数访问,但是可以通过基类提供的公有成员函数访问。公有派生与私有派生的不同点在于基类中的公有成员在派生类中的访问属性。

公有派生时, 基类中的所有公有成员在派生类中也都是公有的。

私有派生时, 基类中的所有公有成员只能成为派生类中的私有成员。

下面我们分别讨论私有派生和公有派生的一些特性。

私有派生

(1 ) 私有派生类对基类成员的访问
由私有派生得到的派生类, 对它的基类的公有成员只能是私有继承。也就是说基类的所有公有成员都只能成为私有派生类的私有成员, 这些私有成员能够被派生类的成员函数访问,但是基类私有成员不能被派生类成员函数访问。

# include using namespace std; class base // 声明一个基类 { int x; public: void setx(int n) { x = n; } void showx () { cout setx( n) ; y = m; } void showxy() { cout // 声明一个基类 int x; public: void setx(int n) { x = n; } void showx () { cout y = n; } void showy() { cout // 声明一个基类 int x; public: void setx(int n) { x = n; } void showx() { cout y = n; } void showy() { cout int x; public: void setx (int n ) { x = n; } void showx() { cout y = n; } void show-sum() { cout public: int f() ; }; class Ypublic X { public: int f(); int g() ; }; void Y∷g() { f() ; // 表示被调用的函数是 Y∷f( ), 而不是 X∷f( ) }

对于派生类的对象的引用,也有相同的结论, 例如:
Y obj;
obj .f( ) ; / / 被调用的函数是 Y∷f( )
如果要使用基类中声明的名字,则应使用作用域运算符限定, 例如:
obj .X∷f( ) ; / / 被调用的函数是 X∷f( )

保护成员的作用

protected 说明符可以放在类声明的任何地方,通常将它放在私有成员声明之后, 公有成员声明之前。类声明的一般格式如下所示:

class 类名 { [private:] 私有数据成员和成员函数 protected: 保护数据成员和成员函数 public: 公有数据成员和成员函数 };

保护成员可以被派生类的成员函数访问,但是对于外界是隐藏起来的, 外部函数不能访问它。因此,为了便于派生类的访问, 可以将基类私有成员中需要提供给派生类访问的成员定义为保护成员。
下面的程序说明类的私有成员、公有成员与保护成员是如何被访问的。

# include < iostream .h > class samp { int a; protected: int b; // 定义变量 b 为保护成员 public: int c; samp(int n, int m) { a = n; b = m; } int geta() { return a ; } int getb() { return b; } }; int main() { samp obj(20, 30); obj.b = 99; // 非法,类的保护成员不能被外部函数访问 obj .c = 50; // 合法,类的公有成员能被外部函数访问 cout a = n; b = m; } }; class derive : public base { int c; public: void setc(int n) { c = n; } void showabc() { cout protected: int a; public: void seta (int sa) { a = sa; } } ; class derive1: private base { protected: int b; public: void setb(int sb) { b = sb; } } ; class derive2: public derive1 { int c; public: void setc(int sc) { c = sc ; } void show( ) { cout public: base() { cout public: derive() // 派生类的构造函数 { cout derive op; return 0 ; }

程序运行结果如下:

Constructing base class
Constructing derived class
Destructing derived class
Destructing base class
构造函数的调用严格地按照先调用基类的构造函数, 后调用派生类的构造函数的顺序执行。析构函数的调用顺序与构造函数的调用顺序正好相反,先调用派生类的析构函数, 后调用基类的析构函数。

2.派生类构造函数和析构函数的构造规则

当基类的构造函数没有参数,或没有显式定义构造函数时, 派生类可以不向基类传递参数,甚至可以不定义构造函数。
派生类不能继承基类中的构造函数和析构函数。当基类含有带参数的构造函数时,派生类必须定义构造函数,以提供把参数传递给基类构造函数的途径。
在 C + + 中,派生类构造函数的一般格式为:

派生类构造函数名(参数表) :基类构造函数名( 参数表) { / /}

其中基类构造函数的参数,通常来源于派生类构造函数的参数表, 也可以用常数值。
下面的程序说明如何传递一个参数给派生类的构造函数和传递一个参数给基类的构造函数。

#include using namespace std; class base { int i; public: base(int n) // 基类的构造函数 { cout cout // 缀上基类的构造函数 cout cout // … }

在定义派生类对象时,构造函数的执行顺序如下:

基类的构造函数对象成员的构造函数派生类的构造函数

撤消对象时,析构函数的调用顺序与构造函数的调用顺序正好相反。
下面这个程序说明派生类构造函数和析构函数的执行顺序。

#include using namespace std; class base { int x; public: base(int i) // 基类的构造函数 { x = i; cout cout // 对象成员构造函数 cout derived obj(5 ); obj.show(); return 0 ; }

程序执行结果如下:
Constructing base class
Constructing base class
Constructing derived class
x = 5
Destructing derived class
Destructing base class
Destructing base class
说明:

当基类构造函数不带参数时, 派生类不一定需要定义构造函数, 然而当基类的构造函数哪怕只带有一个参数,它所有的派生类都必须定义构造函数, 甚至所定义的派生类构造函数的函数体可能为空,仅仅起参数的传递作用。若基类使用缺省构造函数或不带参数的构造函数, 则在派生类中定义构造函数时可略去“∶基类构造函数名(参数表)”; 此时若派生类也不需要构造函数, 则可不定义构造函数。如果派生类的基类也是一个派生类, 则每个派生类只需负责其直接基类的构造,依次上溯。由于析构函数是不带参数的, 在派生类中是否要定义析构函数与它所属的基类无关,故基类的析构函数不会因为派生类没有析构函数而得不到执行, 它们各 自是独立的。

三.多重继承

前面我们介绍的派生类只有一个基类, 这种派生方法称为单基派生或单一继承。当一个派生类具有多个基类时,这种派生方法称为多基派生或多重继承。

1.多重继承的声明

一般形式如下:

class 派生类名: 派生方式 1 基类名 1,,派生方式 n 基类名 n { // 派生类新增的数据成员和成员函数 } ;

冒号后面的部分称基类表,各基类之间用逗号分隔, 其中“派生方式 i”( i = 1, 2, …, n )规定了派生类从基类中按什么方式继承: private 或 public,缺省的派生方式是 private

class z: public x, y { // 类 z 公有继承了类 x,私有继承了类 y // … }; class z: x, public y { // 类 z 私有继承了类 x,公有继承了类 y // … }; class z: public x, public y { // 类 z 公有继承了类 x 和类 y // … };

在多重继承中,公有派生和私有派生对于基类成员在派生类中的可访问性与单继承的规则相同。

#include using namespace std; class X { int a ; public: void setX(int x) { a = x; } void showX() { cout b = x; } void showY() { cout c = x; setY(y) ; } void showZ() { showY(); cout public: int f(); }; class Y { public: int f(); int g(); }; class Zpublic X, public Y { public: int g(); int h(); };

假如定义类 Z 的对象 obj: Z obj;
则以下对函数 f( )的访问是二义的:
obj .f( ) ;

/ / 二义性错误,不知调用的是类 X 的 f( ) ,还是类 Y 的 f( )

使用成员名限定可以消除二义性,例如:
obj .X∷f( ) ;

/ / 调用类 X 的 f( )

obj .Y∷f( ) ;

/ / 调用类 Y 的 f( )

2.多重继承的构造函数与析构函数

多重继承构造函数的定义形式与单继承构造函数的定义形式相似, 只是 n 个基类的构造函数之间用“,”分隔。多重继承构造函数定义的一般形式如下:

派生类构造函数名(参数表) :基类 1 构造函数名 ( 参数表), 基类 2 构造函数名 (参数表),,基类 n 构造函数名(参数表) { // … }

例如,由一个硬件类 Hard 和一个软件类 Soft ,它们共同派生出系统类 System, 声明如下:

class Hard { protected: char bodyname[20]; public: Hard(char * bdnm ); // 基类 Hard 的构造函数 // … }; class Soft { protected: char os[10]; char Lang[15]; public: Soft( char * o, char * lg);// 基类 Soft 的构造函数 // … } ; class System: public Hard, public Soft { private: char owner[10] ; public: System( char * ow, char * bn, char * o, char * lg) // 派生类 System 的构造函数Hard( bn), Soft(o, lg); // 缀上了基类 Hard 和 Soft 的构造函数 // … };

注意:在定义派生类 System 的构造函数时,缀上了 Hard 和 Soft 的构造函数。
再如,现有一个窗口类 window 和一个滚动条类 scrollbar, 它们可以共同派生出一个带有滚动条的窗口,声明如下:

class window { // 定义窗口类 window // … public: window(int top, int left, int bottom, int right); ~window(); // … } ; class scrollbar { // 定义滚动条类 scrollbar // … public: scrollbar(int top, int left, int bottom, int right); ~scrollbar(); // … }; class scrollbarwind∶window,scrollbar { / / 定义派生类 / /public: scrollbarwind(int top, int left, int bottom, int right); ~scrollbarwind(); // … }; scrollbarwind∷scrollbarwind(int top, int left, int bottom, int right)window( top, left,bot tom, right),scrollbar(top, right - 20, bottom, right) { // … }

在这个例子中, 定义派生类 scrollbarwind 的构造函数时, 也缀上了基类 window 和scrollbar 的构造函数。
下面我们再看一个程序,其中类 X 和类 Y 是基类, 类 Z 是类 X 和类 Y 共同派生出来的,请注意类 Z 的构造函数的定义方法。

#include using namespace std; class X { int a; public: X(int sa ) // 基类 X 的构造函数 { a = sa; } int getX() { return a ; } }; class Y { int b; public: Y(int sb) // 基类 Y 的构造函数 { b = sb; } int getY() { return b; } } ; class Z: public X, private Y { // 类 Z 为基类 X 和基类 Y 共同的派生类 int c; public: Z(int sa, int sb, int sc ) :X(sa), Y(sb) // 派生类 Z 的构造函数,缀上 { c = sc ; } // 基类 X 和 Y 的构造函数 int getZ() { return c; } int getY() { return Y::getY(); } }; int main() { Z obj( 2, 4, 6) ; int ma = obj.getX(); cout a = 5; } }; class base1:public base { public: base1() { cout cout cout protected: int a; public: base() { a = 5; } }; class base1:virtual public base { public: base1() { cout cout cout // … }; X one;

定义类 X 的对象 one 时,将产生如下的调用次序:
Z( ) ;
Y( ) ;
X( ) ;

#include using namespace std; class base { int a ; public: base (int sa) { a = sa; cout b = sb; cout c = sc ; cout d = sd; cout // … } ; class derived: public virtual base{ // … } ; 一个基类在作为某些派生类虚基类的同时, 又作为另一些派生类的非虚基类, 这种情况是允许存在的,例如:class B{ // … } ; class Xvirtual public B{ // … } ; class Yvirtual public B{ // … } ; class Zpublic B{ // … } ; class AApublic X, public Y , public Z{ // … } ;

此例中,派生类 AA 由类 X、类 Y 和类 Z 派生而来。AA 与它的间接基类 B 之间的对应关系是:类 B 既是 X、Y 继承路径上的一个虚基类, 也是 Z 继承路径上的一个非虚基类。

收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜