C++ 继承和派生
2013-11-26 21:08
357 查看
派生:
派生类是基类的具体化,而基类是派生类的抽象
派生类的定义:
class 派生类名: [继承方式] 基类名
{ 派生类新增加的成员 };
派生类中声明一个与基类成员相同的成员或者成员函数,会覆盖对应基类的成员或者成员函数
继承的方式:
(1) 公共继承(public):
公用基类成员在公用派生类中的访问属性(私有->不可访问;公用成员->公用;保护成员->保护)
对于基类私有变量只能通过基类的公用成员函数访问,比如stud1.display()。
(2) 私有继承(private):
公用基类成员在公用派生类中的访问属性(私有->不可访问;公用成员->私有;保护成员->私有),
不能访问基类的私有数据成员。对新加入的私有成员和函数,只能在派生类内部调用。
(3) 受保护的继承(protected):
公用基类成员在公用派生类中的访问属性(私有->不可访问;公用成员->保护;保护成员->保护),
不能访问基类的私有数据成员。对新加入的私有成员和函数,只能在派生类内部调用。(在内部相当于是私有的,但是在下层公用派生类中可以被访问。)
派生类的构造函数
(1) 派生类构造函数名(总参数列表) : 基类构造函数名(参数列表) {派生类中新增数据成员初始化语句},例如
Student1 (int n, string nam, char s, int a, sting ad): Student(n, nam, s) // 注意顺序
或者Student1 (int n, string nam, char s, int a, sting ad): Student(n, nam, s), age(a), addr(ad) {}
(2) 有子对象的派生类构造函数:
派生类构造函数名(总参数列表) : 基类构造函数名(参数列表), 子对象名(参数列表) {派生类中新增数据成员初始化语句}
Student1 (int n, string nam, int n1, string nam1, int a, sting ad): Student(n, nam, s), monitor(n1, nam1) {}
(3) 派生类构造函数调用顺序: 基类构造函数 -> 子对象构造函数 -> 派生类构造函数;
(4) 派生类析构函数调用顺序: 派生类析构函数 -> 子对象析构函数 -> 基类析构函数
多重继承:
(1) class D: public A, private B, protected C {类D新增加的成员} // 调用构造函数A->B->C->D
(2) 如果基类中有同名变量,解决二义性的方式就是用当前类的名字来限定,比如Teacher::name. 对于同名函数,如果没有改变,相当于覆盖。
C继承A,B类,每个类中都含同名变量a,C c;解决二义性的方法: c.a,c.A::a,c.B::a;
(3) 多重继承引起的二义性:用基类的名来限定,C c1; c1.A::a=3; c1.A::display(); //注意一定明确变量和函数的继承关系。
虚基类:解决同名函数,节省空间,避免二义性
(1) 虚基类的一般形式:class 派生类名:virtual 继承关系 基类名
(2) 虚基类的初始化(P381):class D: public B, public C {D(int n):A(n),
B(n), C(n) {};} // A为基类,B,C为A的派生类
(3) 在派生类中不仅要负责对其直接基类进行初始化,还要负责对虚基类初始化 //编译系统只执行最后的派生类对虚基类的构造函数的调用,而忽略其他派生类的调用。
基类和派生类的转换 (只有公用派生类才是基类真正的子类型,“大材小用”原则)
A a1; B b1; // A是基类,B是A的派生类
(1) 派生类对象可以向基类对象赋值,例如
a1 = b1; // 单向不可逆
(2) 派生类对象可以初始化基类的引用
A &r = b1; // r并不是b1的别名,而是与b1共享一段存储单元。换句话说是b1基类部分的别名
(3) 指向基类的指针可以指向派生类
A *p = &b1; // p指向的是b1从基类继承的部分
派生类是基类的具体化,而基类是派生类的抽象
派生类的定义:
class 派生类名: [继承方式] 基类名
{ 派生类新增加的成员 };
派生类中声明一个与基类成员相同的成员或者成员函数,会覆盖对应基类的成员或者成员函数
继承的方式:
(1) 公共继承(public):
公用基类成员在公用派生类中的访问属性(私有->不可访问;公用成员->公用;保护成员->保护)
对于基类私有变量只能通过基类的公用成员函数访问,比如stud1.display()。
(2) 私有继承(private):
公用基类成员在公用派生类中的访问属性(私有->不可访问;公用成员->私有;保护成员->私有),
不能访问基类的私有数据成员。对新加入的私有成员和函数,只能在派生类内部调用。
(3) 受保护的继承(protected):
公用基类成员在公用派生类中的访问属性(私有->不可访问;公用成员->保护;保护成员->保护),
不能访问基类的私有数据成员。对新加入的私有成员和函数,只能在派生类内部调用。(在内部相当于是私有的,但是在下层公用派生类中可以被访问。)
派生类的构造函数
(1) 派生类构造函数名(总参数列表) : 基类构造函数名(参数列表) {派生类中新增数据成员初始化语句},例如
Student1 (int n, string nam, char s, int a, sting ad): Student(n, nam, s) // 注意顺序
或者Student1 (int n, string nam, char s, int a, sting ad): Student(n, nam, s), age(a), addr(ad) {}
(2) 有子对象的派生类构造函数:
派生类构造函数名(总参数列表) : 基类构造函数名(参数列表), 子对象名(参数列表) {派生类中新增数据成员初始化语句}
Student1 (int n, string nam, int n1, string nam1, int a, sting ad): Student(n, nam, s), monitor(n1, nam1) {}
(3) 派生类构造函数调用顺序: 基类构造函数 -> 子对象构造函数 -> 派生类构造函数;
(4) 派生类析构函数调用顺序: 派生类析构函数 -> 子对象析构函数 -> 基类析构函数
多重继承:
(1) class D: public A, private B, protected C {类D新增加的成员} // 调用构造函数A->B->C->D
(2) 如果基类中有同名变量,解决二义性的方式就是用当前类的名字来限定,比如Teacher::name. 对于同名函数,如果没有改变,相当于覆盖。
C继承A,B类,每个类中都含同名变量a,C c;解决二义性的方法: c.a,c.A::a,c.B::a;
(3) 多重继承引起的二义性:用基类的名来限定,C c1; c1.A::a=3; c1.A::display(); //注意一定明确变量和函数的继承关系。
虚基类:解决同名函数,节省空间,避免二义性
(1) 虚基类的一般形式:class 派生类名:virtual 继承关系 基类名
(2) 虚基类的初始化(P381):class D: public B, public C {D(int n):A(n),
B(n), C(n) {};} // A为基类,B,C为A的派生类
(3) 在派生类中不仅要负责对其直接基类进行初始化,还要负责对虚基类初始化 //编译系统只执行最后的派生类对虚基类的构造函数的调用,而忽略其他派生类的调用。
基类和派生类的转换 (只有公用派生类才是基类真正的子类型,“大材小用”原则)
A a1; B b1; // A是基类,B是A的派生类
(1) 派生类对象可以向基类对象赋值,例如
a1 = b1; // 单向不可逆
(2) 派生类对象可以初始化基类的引用
A &r = b1; // r并不是b1的别名,而是与b1共享一段存储单元。换句话说是b1基类部分的别名
(3) 指向基类的指针可以指向派生类
A *p = &b1; // p指向的是b1从基类继承的部分