一.原则:
父类/子类
基类/派生类
二.语法:
class 派生类 : [访问限定符] 基类 {
成员
}
例:(成员函数)
#includeusing namespace std; class Father{ public: Father(){ cout << __func__ << endl; } ~Father(){ cout << __func__ << endl; } void FatherTest(){ cout << __func__ << endl; } }; class Son:public Father{ public: Son(){ cout << __func__ << endl; } ~Son(){ cout << __func__ << endl; } }; int main(){ Son s; s.FatherTest(); }
输出:
Father
Son
FatherTest
~Son
~Father
先调用Father的构造函数,先调用son的析构函数
注:
当父类中只有带参构造函数和成员变量(公有),子类只有默认构造函数,则不可编译。
1.但可以使子类的构造函数中调用父类的带参构造函数
Son():Father(10){ }
2.也可以子类构造函数含参数传到父类中,让父类去构造
Son(int n):Father(n)
构造子类对象时:Son s(100);
3.可以继承的基础上再继承 ,例:三角形
#include#include using namespace std; class Triangle{ int a,b,c; public: Triangle(int a,int b,int c):a(a),b(b),c(c){}//构造 int GetLength()const{ return a+b+c; } float GetArea()const{ float h = GetLength()/2.0; return sqrt(h*(h-a)*(h-b)*(h-c)); } }; class IsoscelesTriangle:public Triangle{//等腰三角形 (继承三角形) public: IsoscelesTriangle(int bottom,int side):Triangle(bottom,side,side){} }; class EquilteralTriangle:public IsoscelesTriangle{//等边三角形(继承等腰三角形) public: EquilteralTriangle(int side):IsoscelesTriangle(side,side){} }; int main(){ Triangle t(3,4,5); cout << t.GetLength() << endl; cout << t.GetArea() << endl; EquilteralTriangle et(3); cout << et.GetLength() << endl; cout << et.GetArea() << endl; IsoscelesTriangle it(4,7); cout << it.GetLength() << endl; cout << it.GetArea() << endl; }
三.protected
作用:让派生类能够访问公众不能使用的内部函数
子类内部访问父类成员,只能访问public和protected成员。
也继承了private成员,但是不能访问。
继承方式:
- public无论类内部还是类对象都可以访问。
- protected类对象不可访问,类内部与继承类的内部可以访问。
- private只有类内部可以访问。
- 简看:
四.同名隐藏规则(平时最好不要重名)
成员变量同名,会隐藏基类。
#includeusing namespace std; class base{ public: int n; void Printbase(){ cout << &n << ":" << n << endl; } }; class Derive:public base{ public: int n; void PrintDerive(){ cout << &n << ":" << n << endl; } }; int main(){ Derive d; d.n = 100; d.Printbase() ; d.PrintDerive() ; }
输出为:0x6ffe10:0
0x6ffe14:100
要想避免这种情况,可以专门给基类赋值
d.base::n = 10;
成员函数同名 ,大体与成员变量情况相同。
注:假如父类中有同名重载函数(函数名相同,参数不相同),子类中没有。当直接调用该函数时会出错,因为一旦在子类中找到重名函数,就不会再去父类中找重载函数,只有当子类中没有重名函数,才会再去父类中找函数。解决方法:
①在子类中写:using base::Test;
②在main中写:d.base::Test(20);
五.赋值兼容原则
概念:在任何需要基类(父类)对象的地方都可以使用公有的派生类(子类)对象来代替。反之,不可。
1.子类的对象可以直接赋值给父类的对象。
base base; Derive derive; base = derive;
2.子类的对象可以初始化父类的引用。
Derive derive; base& base = derive;
3.子类对象的地址可以赋给指向父类的指针,指向父类对象的指针变量也可以指向子类对象。
Derive derive; base* base = &derive;
注:还可以用此来解决同名隐藏
base& f = d;//d是子类对象 f.Test(); //此时调用的是父类的 //or: base* p = d; p->Test();
六.补充:
当子类和父类有拷贝构造函数和赋值运算符重载函数时,在子类中需要负责父类的拷贝和赋值
(最好使用默认的)
Derice(const Derice& d):base(d){
n = d.n;
}
Derice& operator=(const Derice&){
n = d.n;
base& b = *this;
b = d; //赋值兼容
return* this;
}
七.多重继承(java不允许)
class 类名 : public 基类1,public 基类2{
};
#includeusing namespace std; class base1{ int n; public: base1(int n):n(n){} void PrintN(){ cout <<__func__<< "(" << n << ")" << endl; } }; class base2{ int m; public: base2(int m):m(m){} void PrintM(){ cout <<__func__<< "(" << m << ")" << endl; } }; class Derive:public base1,public base2{ public: Derive(int n,int m):base1(n),base2(m){ } }; int main(){ Derive d(1,2); d.PrintN() ; d.PrintM() ; }
输出:PrintN(1)
PrintM(2)
1.两个父类中不允许出现重名函数
2.钻石继承/菱形继承
例:B,C继承了A,D继承了B,C。下列代码会出现什么情况?
#includeusing std::cout; using std::endl; class A{ public: void test(); private: int id; }; void A::test(){ cout << __func__ << endl; } class B : public A {}; class C : public A {}; class D : public B,public C{}; int main(){ cout << "A size:" << sizeof(A) << endl; cout << "B size:" << sizeof(B) << endl; cout << "C size:" << sizeof(C) << endl; cout << "D size:" << sizeof(D) << endl; D d; d.test(); }
会报错,不确定test()调用的是B的还是C的,应在前加上访问限定符,d.B::test()
- 虚继承
为了节省空间,可以将B、C对A的继承定义为虚拟继承,而A就成了虚拟基类
class A; class B:vitual public A; class C:vitual public A; class D:public B,public C;
子类构造时初始化虚基类(假如有成员时)
Derice(int n,int m):n(n),base1(m),base2(m),base(m){}
此时就可以调用重名函数,不用加访问限定符



