一、基础知识
1、基类与派生类
(1)继承语法形式:
class 派生类名:基类名表
{
数据成员和成员函数声明
};
基类类名表构成:
访问控制 基类名
访问控制有三种{public:公有继承
private:私有继承
protected:保护继承
}
无论哪种类型都不能直接访问基类私有成员。
(2)派生类的生成过程
吸收基类成员:除构造和析构函数外
改造基类成员:通过在派生类中定义同名成员屏蔽在派生类中不起作用的部分基类成员。
添加新成员
例1:
#include<iostream>
using namespace std ;
class A
{ public :
void get_XY()
{ cout << "Enter two numbers of x, y : " ; cin >> x >> y ; }
void put_XY() { cout << "x = "<< x << ", y = " << y << '\n' ; }
protected: int x, y;
};
class B : public A
{ public :
int get_S() { return s ; };
void make_S() { s = x * y ; };
protected: int s;
};
class C : public B
{ public :
void get_H() { cout << "Enter a number of h : " ; cin >> h ; }
int get_V() { return v ; }
void make_V() { make_S(); v = get_S() * h ; }
protected: int h, v;
};
int main()
{ A objA ;
B objB ;
C objC ;
cout << "It is object_A :\n" ;
objA.get_XY() ;
objA.put_XY() ;
cout << "It is object_B :\n" ;
objB.get_XY() ;
objB.make_S() ;
cout << "S = " << objB.get_S() << endl ;
cout << "It is object_C :\n" ;
objC.get_XY() ;
objC.get_H();
objC.make_V() ;
cout << "V = " << objC.get_V() << endl ;
}
A类做基类,x,y声明为受保护类型数据成员,可以在派生类中引用,B类继承A中数据成员,新增数据成员s,make_s使用基类中的数据成员,求面积,C类继承B类,并增加v,h,使用B类中数据成员求体积v.
(3)重名成员
派生类中定义与基类同名成员,屏蔽基类成员,如在派生类中使用基类同名成员,显式地使用类名限定符 类名:成员
例2:
#include<iostream>
using namespace std ;
class A
{ public:
int a1, a2 ;
A( int i1=0, int i2=0 ) { a1 = i1; a2 = i2; }
void print()
{ cout << "a1=" << a1 << '\t' << "a2=" << a2 << endl ; }
};
class B : public A
{ public:
int b1, b2 ;
B( int j1=1, int j2=1 ) { b1 = j1; b2 = j2; }
void print()
{ cout << "b1=" << b1 << '\t' << "b2=" << b2 << endl ; }
void printAB()
{ A::print() ;
print() ;
}
};
int main()
{ B b ;
b.A::print();
b.printAB(); }
A、B类中都有成员print(),如果想调用A类的print(),必须在前面加基类名限定
(4)派生类中访问静态数据成员
定义的静态成员,将被所有派生类共享
访问静态成员的形式
类名::成员或对象名.成员。
2、基类初始化:
(1)创建派生类对象时用指定参数调用基类的构造函数进行初始化
派生类构造函数声明格式为:
派生类构造函数(变元表):基类(变元表)、对象成员1(变元表)
构造函数执行顺序:基类——对象成员——派生类
例3:
#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 ( ) ; }
派生类构造函数中前两个参数对基类数据成员初始化,中间两个参数对对象成员初始化,最后一个参数对派生类新增成员初始化
(2)派生类构造函数和析构函数的使用原则
基类的构造函数和析构函数不能继承
如果基类没有定义构造函数或是定义无参构造函数,派生类也不用定义构造函数。
如果基类无无参构造函数,派生类必须定义构造函数
派生类是否定义析构函数与所属基类无关
如果派生类基类也是派生类,每个派生类只负责直接基类的构造
(3)派生类析构函数
当派生类中不含对象成员时
构造函数的执行顺序是:基类→派生类;
析构函数的执行顺序是:派生类→基类。
当派生类中含有对象成员时
构造函数的执行顺序:基类→对象成员→派生类;
析构函数的执行顺序:派生类→对象成员→基类。
3、多继承
一个类有多个直接基类的继承关系称为多继承
多继承声明语法
class 派生类名: 访问控制 基类名1 , 访问控制 基类名2 , … , 访问控制 基类名n
{
数据成员和成员函数声明
};
多继承在实际中不常用,因此不作详细介绍,了解即可。
4、赋值兼容原则
(1)在程序中需要使用基类对象的地方都可以用公有派生类的对象代替
派生类对象可以赋值给基类对象:
例:Base b;
Derived d;
b=d;
b中所有数据成员都具有对象d中对应数据成员的值
派生类对象可以初始化基类引用:
例:Derived d;
Base&br=d;
派生类对象可以赋给指向基类的指针:
例:Derived d;
Base *bptr=&d;
派生类对象可以赋给指向基类对象的指针
Derived *dptr,obj;
dptr=&obj;
Base*bptr=dptr;
注意:替代之后,派生类对象可以作为基类对象使用,但只能使用基类成员。
(2)一个基类对象派上作用的地方派生类一样派上作用,反之不然
例如:
class Person {…};
class Student : publicPerson { … };
void eat(Person &p){};
void study(Student&s){};
void main( )
{
Person p;
Student s;
eat(p);
eat(s);
study(s);
study(p);
}
eat(s)可以,但study(p)会发生错误,不能用基类替代派生类
(3)赋值兼容应注意的问题:
指向基类的指针可以指向公有派生类的对象,但不允许指向它的私有派生类的对象。
允许将一个声明为指向基类的指针指向其公有派生类对象,但是不能将一个声明为指向派生类对象的指针指向基类对象。
声明为指向基类对象的指针,当其指向公有派生类对象时,只能用它来直接访问派生类中从基类继承来的成员,而不能直接访问公有派生类的定义的成员。
二、心得体会
这一章学习了继承,继承就是从一个已有类中继承数据成员,当有多个类有着相同的数据成员时,可以采用这种方法,从而大大缩短代码长度。因此,继承其实,不是一开始就是设计好的,而是写类时根据类的关系来设计的。在图书馆管理系统中,图书与用户有着共同的记录类,就可以考虑把这个记录类单独拿出来,做一个基类,图书和用户做派生类从其中继承,同时,管理端和用户端有着同样的图书向量也可以考虑做一个继承。不过,我在继承数据成员的处理上,还有一些问题,还需要进一步研究。