类的继承和派生允许我们在保持原有类的基础上,进行修改和扩充。
原有的类称为基类或父类,新类称为派生类或子类。
关于类成员的权限
类成员可以分为:不可访问成员、保护成员、私有成员、公有成员。
不可访问成员:从基类私有成员继承而来的,派生类无法直接访问。
保护成员:类内部可以直接访问。外部不可直接访问。其子类可以访问。
私有成员:类内部可以直接访问。外部不可直接访问。其子类不可以访问。
公有成员:大家都可以访问。
#include<iostream>
using namespace std;
class A
{
public: //公有成员
int p1; //公有成员类内外都可以访问
void p(){ //类内访问
p1=1;
p2=2;
p3=3;
}
private: //私有成员
int p2; //私有成员只有类内可以访问
void pp(){ //类内访问
p1=11;
p2=22;
p3=33;
}
protected: //保护成员
int p3; //保护成员只有类内可以访问
void ppp(){ //类内访问
p1=111;
p2=222;
p3=333;
}
};
int main()
{
A a1;
a1.p1=1; //类外访问
return 0;
}
继承方式
公有继承:基类的公有成员和保护成员在派生类里属性不变,基类的私有成员在派生类里变成不可访问成员。
私有继承:基类的公有成员和保护成员在派生类里变成私有成员,基类的私有成员在派生类里变成不可访问成员。
保护继承:基类的公有成员在派生类里变成保护成员,基类的私有成员在派生类里属性不变,基类的私有成员在派生类里变成不可访问成员。
#include<iostream>
using namespace std;
class A //在A类内p1为公有成员,p2为私有成员,p3为保护成员
{
public:
int p1;
void show_p(){
p1=1;
p2=2;
p3=3;
cout<<"p1="<<p1<<" p2="<<p2<<" p3="<<p3<<endl;
}
private:
int p2;
protected:
int p3;
};
class B:public A //B公有继承了A,p1在B类内为公有成员,p2为不可访问成员,p3为保护成员
{
public:
void show_b(){
p1=11;
p3=33;
cout<<"p1="<<p1<<" p3="<<p3<<endl;
}
};
class C:private A //C私有继承了A,p1在C类内为私有成员,p2为不可访问成员,p3为私有成员
{
public:
void show_c(){
p1=111;
p3=333;
cout<<"p1="<<p1<<" p3="<<p3<<endl;
}
};
class D:protected A //D保护继承了A,p1在D类内为保护成员,p2为不可访问成员,p3为保护成员
{
public:
void show_d(){
p1=1111;
p3=3333;
cout<<"p1="<<p1<<" p3="<<p3<<endl;
}
};
int main()
{
A a1;
B b1;
C c1;
D d1;
b1.show_b();
c1.show_c();
d1.show_d();
return 0;
}
当派生类继承多个基类时,利用作用域分辨符避免二义性
#include<iostream>
class A{
public:
int a;
};
class B{
public:
int a;
};
class C:public A,public B{ //C类内有a具有二义性
public:
int c;
};
int main()
{
C c1:a=2;
c1.A::a=1; //利用::来确定访问的是哪个
c1.B::a=2;
std::cout<<c1.A::a<<" "<<c1.B::a<<std::endl;
return 0;
}
当派生类多次继承同种基类时,可以利用虚基类使其通用,在内存中只占一个副本
#include<iostream>
using namespace std;
class A{
public:
int a;
};
class B1:virtual public A{ //将A设为虚基类
public:
void show(){
cout<<"B1.a="<<a<<endl;
}
};
class B2:virtual public A{ //将A设为虚基类
public:
void show(){
cout<<"B2.a="<<a<<endl;
}
};
class C:public B1,public B2{ //C类里有共同基类A
};
int main()
{
C c;
c.a=1;
c.B1::show();
c.B2::show();
}
结果
B1.a=1
B2.a=1
虚基类的构造函数及析构函数
当共同基类有构造函数时,其如果是虚基类,则只运行一次构造函数;析构函数同理
#include<iostream>
using namespace std;
class A0{ //共同基类
public:
A0(){ //构造函数
a=1;
cout<<"init A0.a="<<a<<endl;
}
int a;
~A0(){ //析构函数
cout<<"A0.a="<<a<<endl;
}
};
class A1: virtual public A0{ //A0为虚基类
public:
A1(){
a=2;
cout<<"init A1.a="<<a<<endl;
}
~A1(){
cout<<"A1.a="<<a<<endl;
}
};
class A2: virtual public A0{ //A0为虚基类
public:
A2(){
a=3;
cout<<"init A2.A="<<a<<endl;
}
~A2(){
cout<<"A2.A="<<a<<endl;
}
};
class Derived: public A1,public A2{
public:
Derived(){
a=5;
cout<<"init Derived.a="<<a<<endl;
}
~Derived(){
cout<<"Derived.a="<<a<<endl;
}
};
int main()
{
Derived d;
return 0;
}
结果:
init A0.a=1
init A1.a=2
init A2.A=3
init Derived.a=5
Derived.a=5
A2.A=5
A1.a=5
A0.a=5
隔代继承访问,小心产生歧义基类
#include<iostream>
using namespace std;
class A{
public:
int a;
};
class A1{
public:
int a;
};
class B:public A,public A1{
};
class B1:public A,public A1{
};
class C:public B, public B1{ //C类内包含四个int a
};
int main()
{
C c;
c.B::A::a=2;
return 0;
}
隔代继承访问比较坑的一点是你的编译器可能会报错
错误:‘A’ 是 ‘C’ 的有歧义的基类
这时候换个编译器试试,我用VS2010可以编译成功
当子类和父类的函数发生重命时,会发生隐藏
如果子类函数与父类函数同名,不管参数是否相同,父类函数都将被隐藏。
#include<iostream>
using namespace std;
class A{
public:
int a;
A(){
a=1;
}
void show(){ //父类函数
cout<<"A.a="<<a<<endl;
}
};
class B:public A{
public:
int b;
B(){
b=2;
}
void show(){ //子类函数,与父类函数重名,父类函数被隐藏
cout<<"B.b="<<b<<endl;
}
};
int main()
{
B b;
B *p;
p=&b;
b.show();
}
B.b=2
当基类指针指向派生类对象
1)该指针只能访问派生类对象中的继承该基类的部分
2)当该派生类多次继承该基类时,指针一般默认访问的是血缘关系最近的基类部分。
3)如果有同辈份的二个以上的相同基类,则须通过间接指针来访问
#include<iostream> using namespace std; class A{ public: int a; A(){ cout<<"begin A"<<endl; a=1; } void show(){ cout<<"A.a="<<a<<endl; } ~A(){ cout<<"over A"<<endl; } }; class C0:public A{ public: C0(){ a=33; } }; class C:public A{ public: C(){ a=22; } }; class B:public C,public A{ //C类当前二次继承了A类 public: int b; B(){ cout<<"begin B"<<endl; b=2; } void show1(){ cout<<"B.b="<<b<<endl; } ~B(){ cout<<"over b"<<endl; } }; int main() { A *p; B b; p=&b; p->show(); //这里默认访问的是关系近的A;
p->B::A::show(); //这里指明要访问关系远点的A; }
结果begin A begin A begin B A.a=1 A.a=2 over b over A over A
当派生类多次继承的基类关系一样近时
如果我们要用基类指针访问该派生类,须通过间接指针class B:public C,public C0{ public: int b; B(){ cout<<"begin B"<<endl; b=2; } void show1(){ cout<<"B.b="<<b<<endl; } ~B(){ cout<<"over b"<<endl; } };
int main() { B b; C *p; p=&b; A *pl=p; pl->show(); }
结果begin A begin A begin B A.a=22 over b over A over A