一,基础知识
1,类之间的关系
继承:在已有类的基础上创建新类的过程
一个 B 类继承A类,或称从类 A 派生类 B
类 A 称为基类(父类),类 B 称为派生类(子类)
2,基类和派生类
(1)类继承关系的语法形式
class 派生类名 : 基类名表
{
数据成员和成员函数声明
};
基类名表 构成
访问控制 基类名1, 访问控制 基类名2 ,… , 访问控制 基类名n
(2)访问控制 表示派生类对基类的继承方式,使用关键字:
public 公有继承
private 私有继承
protected 保护继承
(3)派生类的生成过程经历了三个步骤:
a 吸收基类成员(全部吸收(构造、析构除外),但不一定可见)
b 改造基类成员
c 添加派生类新成员
a 吸收基类成员:在C++的继承机制中,派生类吸收基类中除构造函数和析构函数之外的全部成员。
b 改造基类成员:通过在派生类中定义同名成员(包括成员函数和数据成员)来屏蔽(隐藏)在派生类中不起作用的部分基类成员。
c 添加新成员:仅仅继承基类的成员是不够的,需要在派生类中添加新成员,以保证派生类自身特殊属性和行为的实现。
3,重名成员:派生类定义了与基类同名的成员,在派生类中访问同名成员时屏蔽(hide)了基类的同名成员。
在派生类中使用基类的同名成员,显式地使用类名限定符:类名 :: 成员
4,派生类中访问静态成员
(1)基类定义的静态成员,将被所有派生类共享(基类和派生类共享基类中的静态成员)
(2)根据静态成员自身的访问特性和派生类的继承方式,在类层次体系中具有不同的访问性质 。
(3) 派生类中访问静态成员,用以下形式显式说明:
类名 :: 成员或通过对象访问 对象名.成员
5,基类的初始化
在创建派生类对象时用指定参数调用基类的构造函数来初始化派生类继承基类的数据。
派生类构造函数声明为:
派生类构造函数 ( 变元表 ) : 基类 ( 变元表 ) , 对象成员1( 变元表 )… 对象成员n ( 变元表 ) ;
构造函数执行顺序:基类 ? 对象成员 派生类
6,派生类构造函数和析构函数的定义规则
派生类构造函数和析构函数的使用原则
(1)基类的构造函数和析构函数不能被继承;
(2)如果基类没有定义构造函数或有无参的构造函数,派生类也可以不用定义构造函数;
(3)如果基类无无参的构造函数,派生类必须定义构造函数;
(4)如果派生类的基类也是派生类,则每个派生类只负责直接基类的构造;
(5)派生类是否定义析构函数与所属的基类无关
7,派生类构造函数的定义:在C++中,派生类构造函数的一般格式为:
派生类::派生类名(参数总表):基类名(参数表)
{
// 派生类新增成员的初始化语句
}
注意:这是基类有构造函数且含有参数时使用
8,派生类析构函数
(1)当派生类中不含对象成员时
a 在创建派生类对象时,构造函数的执行顺序是:基类的构造函数→派生类的构造函数;
b 在撤消派生类对象时,析构函数的执行顺序是:派生类的析构函数→基类的析构函数。
(2)当派生类中含有对象成员时
a 在定义派生类对象时,构造函数的执行顺序:基类的构造函数→对象成员的构造函数→派生类的构造函数;
c 在撤消派生类对象时,析构函数的执行顺序:派生类的析构函数→对象成员的析构函数→基类的析构函数。
一个类有多个直接基类的继承关系称为多继承
多继承声明语法
class 派生类名 : 访问控制 基类名1 , 访问控制 基类名2 , … , 访问控制 基类名n
{
数据成员和成员函数声明
1,类之间的关系
继承:在已有类的基础上创建新类的过程
一个 B 类继承A类,或称从类 A 派生类 B
类 A 称为基类(父类),类 B 称为派生类(子类)
2,基类和派生类
(1)类继承关系的语法形式
class 派生类名 : 基类名表
{
数据成员和成员函数声明
};
基类名表 构成
访问控制 基类名1, 访问控制 基类名2 ,… , 访问控制 基类名n
(2)访问控制 表示派生类对基类的继承方式,使用关键字:
public 公有继承
private 私有继承
protected 保护继承
(3)派生类的生成过程经历了三个步骤:
a 吸收基类成员(全部吸收(构造、析构除外),但不一定可见)
b 改造基类成员
c 添加派生类新成员
a 吸收基类成员:在C++的继承机制中,派生类吸收基类中除构造函数和析构函数之外的全部成员。
b 改造基类成员:通过在派生类中定义同名成员(包括成员函数和数据成员)来屏蔽(隐藏)在派生类中不起作用的部分基类成员。
c 添加新成员:仅仅继承基类的成员是不够的,需要在派生类中添加新成员,以保证派生类自身特殊属性和行为的实现。
3,重名成员:派生类定义了与基类同名的成员,在派生类中访问同名成员时屏蔽(hide)了基类的同名成员。
在派生类中使用基类的同名成员,显式地使用类名限定符:类名 :: 成员
4,派生类中访问静态成员
(1)基类定义的静态成员,将被所有派生类共享(基类和派生类共享基类中的静态成员)
(2)根据静态成员自身的访问特性和派生类的继承方式,在类层次体系中具有不同的访问性质 。
(3) 派生类中访问静态成员,用以下形式显式说明:
类名 :: 成员或通过对象访问 对象名.成员
5,基类的初始化
在创建派生类对象时用指定参数调用基类的构造函数来初始化派生类继承基类的数据。
派生类构造函数声明为:
派生类构造函数 ( 变元表 ) : 基类 ( 变元表 ) , 对象成员1( 变元表 )… 对象成员n ( 变元表 ) ;
构造函数执行顺序:基类 ? 对象成员 派生类
6,派生类构造函数和析构函数的定义规则
派生类构造函数和析构函数的使用原则
(1)基类的构造函数和析构函数不能被继承;
(2)如果基类没有定义构造函数或有无参的构造函数,派生类也可以不用定义构造函数;
(3)如果基类无无参的构造函数,派生类必须定义构造函数;
(4)如果派生类的基类也是派生类,则每个派生类只负责直接基类的构造;
(5)派生类是否定义析构函数与所属的基类无关
7,派生类构造函数的定义:在C++中,派生类构造函数的一般格式为:
派生类::派生类名(参数总表):基类名(参数表)
{
// 派生类新增成员的初始化语句
}
注意:这是基类有构造函数且含有参数时使用
8,派生类析构函数
(1)当派生类中不含对象成员时
a 在创建派生类对象时,构造函数的执行顺序是:基类的构造函数→派生类的构造函数;
b 在撤消派生类对象时,析构函数的执行顺序是:派生类的析构函数→基类的析构函数。
(2)当派生类中含有对象成员时
a 在定义派生类对象时,构造函数的执行顺序:基类的构造函数→对象成员的构造函数→派生类的构造函数;
c 在撤消派生类对象时,析构函数的执行顺序:派生类的析构函数→对象成员的析构函数→基类的析构函数。
例:
-
-
class base
-
{
-
public:
-
base(){ cout<< "constructing base class"<< endl;}
-
~base(){ cout<< "destructing base class"<< endl; }
-
};
-
class subs: public base
-
{
-
public:
-
subs(){ cout<< "constructing sub class"<< endl;}
-
~subs(){ cout<< "destructing sub class"<< endl;}
-
};
-
void main()
-
{
-
subs s;
-
}
-
/* 运行结果:constructing base class
-
constructing sub class
-
destructing sub class
-
destructing base class
-
*/
一个类有多个直接基类的继承关系称为多继承
多继承声明语法
class 派生类名 : 访问控制 基类名1 , 访问控制 基类名2 , … , 访问控制 基类名n
{
数据成员和成员函数声明
};
*在创建派生类对象时用指定参数调用基类的构造函数来初始化派生类继承基类的数据
*派生类构造函数声明为:
派生类构造函数 ( 变元表 ) : 基类 ( 变元表 ) , 对象成员1( 变元表 )
… 对象成员n ( 变元表 ) ;
*构造函数执行顺序:基类--对象成员--派生类
示例:
-
#include <iostream>
-
using namespace std ;
-
class parent_class
-
{ int data1 , data2 ;
-
public :
-
parent_class ( int p1 , int p2 ) { data1 = p1; data2 = p2; }
-
int inc1 () { return ++ data1; }
-
int inc2 () { return ++ data2 ; }
-
void display () {cout << "data1=" << data1 << " , data2=" << data2 << endl ; }
-
};
-
class derived_class : private parent_class
-
{ int data3 ;
-
parent_class data4 ;
-
public:
-
derived_class ( int p1 , int p2 , int p3 , int p4 , int p5 ): parent_class ( p1 , p2 ) , data4 ( p3 , p4 )
-
{ data3 = p5 ; }
-
int inc1 ( ) { return parent_class :: inc1 ( ) ; }
-
int inc3 ( ) { return ++ data3 ; }
-
void display ( )
-
{ parent_class :: display ( ) ; data4.display ( ) ;
-
cout << " data3= " << data3 << endl ;
-
}
-
} ;
-
int main ( )
-
{ derived_class d1 ( 17 , 18 , 1 , 2 , -5 ) ; d1 . inc1 ( ) ; d1 . display ( ) ; }
-
**派生类构造函数和析构函数的定义规则:
派生类构造函数和析构函数的使用原则:
-基类的构造函数和析构函数不能被继承;
-如果基类没有定义构造函数或有无参的构造函数, 派生类也可以不用定义构造函数;
-如果基类无无参的构造函数,派生类必须定义构造函数;
-如果派生类的基类也是派生类,则每个派生类只负责直接基类的构造;
-派生类是否定义析构函数与所属的基类无关.
总结:通过使用继承,可以节省大量重复代码,节省了工作量
公有继承建立is-a的关系,这意味着派生类对象也应该是某种基类对象。如果要将类用作基类,则可以将成员声明成保护的,二不是私有的。这样,派生类可以直接访问这些成员。然而,使用私有成员通常可以减少出现编程问题的可能性;如果希望派生类可以重新定义基类的方法,可以运用关键字virtual声明它是虚的;每个派生类都有他自己的构造函数,在使用派生类构造函数之前,首先调用基类构造函数,同样析构函数也一样。