继承与派生

来源:互联网 发布:神话刷号软件 编辑:程序博客网 时间:2024/06/14 00:49
派生:在基类的基础上建立新的类                                                                                                                                                                                                        
继承:新类从已有类那里获得已有的特性
继承的方向:由派生类指向基类
一个派生类只从一个基类派生:单继承
一个派生类有多个基类:多重继承
派生类是基类的具体,基类是派生类的抽象
1、声明方式
假设已声明基类student,通过单继承建立派生类:
class Student1: public Student
{
public:
void display_1(){}
private:
int age;
string addr;
};
表示公有继承
继承方式:公有、私有、保护,默认为私有继承。
2、派生类的构成
(1)从基类接收成员:派生类把基类全部成员(不包括构造和析构)接收过来,会造成数据冗余
(2)调整从基类接收的成员:可改变基类成员在派生类中的访问属性,可以声明与基类同名的成员,则可以直接覆盖。如果为同名函数,函数参数表也必须相同否则是重载而不是覆盖
(3)声明派生类时增加成员
3、派生类成员的访问属性
(1)基类成员函数访问基类成员(可以)
(2)派生类成员函数访问自己增加的成员(可以)
(3)基类成员函数访问派生类成员(不可以)
(4)派生类成员函数访问基类成员
(5)派生类外访问派生类成员(可访问公有成员、不可以访问私有成员)
(6)派生类外访问基类成员
4和6的情况与继承方式有关
公有继承:基类的公有成员和保护成员保持其原有的访问属性,私有成员仍为基类私有
私有继承:基类的公有成员和保护成员变为派生类的私有,私有成员仍为基类私有
保护继承:基类的公有成员和保护成员变为派生类的保护,私有成员仍为基类私有,把基类原有的公有成员和私有成员保护起来,不让类外任意访问。
保护成员是指不能被外界引用只能被派生类成员引用
不能通过派生类对象引用私有基类继承过来的任何成员
派生类成员函数不能访问私有基类的私有成员
保护成员可以被派生类成员函数引用
派生类虽然不可以访问基类的私有成员,但可以通过基类的成员函数访问到其私有成员

4、派生类的构造函数和析构函数
基类的构造函数不能继承,在声明派生类时,派生类没有把基类的构造函数继承过来,因此对继承过来的基类成员初始化工作也要由派生类构造函数承担。
派生类在设计构造函数时,需要考虑基类数据成员的初始化,和派生类新增成员的初始化
class Student1:public Student
{
public :
//基类构造函数的参数列表
//本类的数据成员初始化
//基类构造函数 只需写实参,是调用基类构造函数
Student1(int n, string nam, char s , int a, string ad)  :Student(n, nam,s) 
{
age = a;
addr = ad;
}
void show();

//函数体中只对派生类的新增数据成员初始化
~Student1(){}              //派生类的析构函数
private:
int age;
string addr;
};
构造函数也可在类内声明,在类外定义
class Student1:public Student
{
public :

Student1(int n, string nam, char s , int a, string ad)
{
age = a;
addr = ad;
}
void show();

//函数体中只对派生类的新增数据成员初始化
~Student1(){}              //派生类的析构函数
private:
int age;
string addr;
};
Student1::Student1(int n, string nam, char s , int a, string ad)  :Student(n, nam,s) 
{
age = a;
addr = ad;
}


可以使用初始化表:
Student1(int n, string nam, char s , int a, string ad)  :Student(n, nam,s)  ,age(a), addr(ad){}

建立一个对象的构造函数时,执行构造函数的顺序:
(1)派生类构造函数先调用基类构造函数
(2)再执行派生类构造函数本身
派生类对象释放时,先执行派生类析构函数,再执行基类析构函数

5、有子对象的派生类的构造函数
类中的数据成员可以包含类对象
Student s1;

class Student1:public Student
{
public :
//基类构造函数的参数列表
//本类的数据成员初始化
//基类构造函数 只需写实参,是调用基类构造函数
//包含子对象的派生类构造函数
Student1(int n, string nam, char s , int a, string ad)  :Student(n, nam,s)  ,monitor(n1, nam1)
{
age = a;
addr = ad;
}
void show();

//函数体中只对派生类的新增数据成员初始化
~Student1(){}              //派生类的析构函数
private:
int age;
string addr;
Student monitor;
};

不能再声明派生类时对其初始化Student monitor (10001, "lisun");
因为类是抽象的类型,不具有具体的数据
因此建立一个对象的构造函数时,包括三部分:
(1)对基类数据成员初始化
(2)对子对象数据成员初始化
(3)对派生类数据成员初始化
6、多层派生时的构造函数
基类构造函数的首部:
Student(int n, string nam)
派生类Student1的构造函数的首部
Student(int n, string nam, int a):Student(n, nam)
派生类Student2 的构造函数的首部
Student2(int n , string nam, int a, int s):Student1(n,nam,a)
声明student2对象时, 调用student2的构造函数,
初始化顺序为:
基类、student1、student2

7、派生类构造函数的特殊形式
1 派生类构造函数体为空。
此构造函数的作用只是将参数传递给基类构造函数和子对象。
2 如果基类中没有定义构造函数,或定义了没有参数的构造函数,则定义派生类构造函数时可以不写基类构造函数。

8、多重继承
允许一个派生类同时继承多个基类
class D: public A, private B, protected C
{
}
构造函数的形式与单继承时构造函数的形式基本相同。先调用基类的构造函数,再执行派生类构造函数的函数体。
成员同名的二义性,要指明作用域。用基类的名字来限定。
如果两个基类和派生类三者都有同名成员,基类同名成员在派生类中将会被屏蔽。
A、B同时从N中继承的成员,C多继承AB ,在C中无法区别是类A中从基类N继承下来的成员还是类B中从基类继承下来的成员,应当通过类N的直接派生类名来指出要访问的是类N的哪一个派生类中的基类成员。
9、虚基类
继承间接共同基类时,只保留一份成员。
将A声明为虚基类:
class A
{...};
class B: virtual public A
{};
class C: virtual public A
{};
注意:虚基类不是在声明基类时声明,是在声明继承方式时声明。应当在基类的所有直接派生类中声明为虚基类,否则仍然出现对基类的多次继承
之前派生类构造函数只需对其直接基类初始化,对于virtual 基,在最后派生类中,不仅要对直接基类初始化,也要对虚基类初始化。
10、基类与派生类的转换
(1)派生类对象可以向基类对象赋值
基类和派生类对象间有赋值兼容关系,由于派生类中包含基类继承的成员,因此可以将派生类赋值给基类对象,在赋值时,舍弃派生类自己的成员。(赋值针对的是数值成员,对成员函数不存在赋值的问题)
A a1; //定义基类对象
B b1;//定义公有派生类对象
a1 = b1;
只能用子类对象对基类对象赋值,而不能用基类对象对子类对象赋值,同一基类的不同派生类之间不能赋值。
(2)派生类对象可以向基类对象的引用赋值,或初始化
A a1;
B b1;
A &r = a1;
可改为: A &r = b1;
或保留A &r = a1;
r = b1;
此时r只是b1中基类部分的别名,r与b1中基类部分共享同一段存储单元。
(3)若函数的参数是基类对象或基类对象的引用,实参可用派生类对象
(4)指向基类对象的指针变量可以指向派生类对象。(指向基类对象的指针只能访问派生类中的基类成员,不能访问增加的成员。

11、继承与组合
继承:是的关系
组会:有的关系

0 0
原创粉丝点击