一、继承的基本语法
基类(父类)
派生类(子类)
继承:减少重复代码
class 子类 :public 父类
{
}
二、继承方式
基类:public权限、protected权限、private权限
1、公共继承(除私有,其他权限和父类一模一样)
共有继承:基类public权限(任然在派生类public)、
基类protected权限(任然在派生类protected)、
基类private(不可访问)
2、保护继承(除私有,其他全部变为保护)
保护继承:基类public权限(在派生类protected)、
基类protected权限(任然在派生类protected)、
基类private(不可访问)
3、私有继承(除私有,其他全部变为私有)
私有继承:基类public权限(在派生类private)、
基类protected权限(在派生类private)、
基类private(不可访问)
父类的私有权限内容,派生类均不可访问
#include<iostream>
using namespace std;
class Base
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
//1、公共继承
class Son1 :public Base
{
public:
void func()
{
m_A = 10; //共有
m_B = 10; //保护
//m_C = 10; ×
}
};
void test01()
{
Son1 s1;
s1.m_A = 10;
//s1.m_B = 10; ×
}
//2、保护继承
class Son2 :protected Base
{
public:
void func()
{
m_A = 10; //保护
m_B = 10; //保护
//m_C = 10; ×
}
};
void test02()
{
Son2 s2;
//s2.m_A = 10; ×
//s2.m_B = 10;
}
//3、私有继承
class Son3 :private Base
{
void func()
{
m_A = 10; //私有
m_B = 10; //私有
//m_C = 10; ×
}
};
class GrandSon3 :public Son3
{
void func()
{
//m_A = 10; ×
//m_B = 10; ×
}
};
void test03()
{
Son3 s3;
//s3.m_A = 10; ×
}
int main()
{
system("pause");
return 0;
}
三、继承中的对象模型
父类中非静态成员都会被子类继承下去
父类中私有成员属性,是被编译器隐藏了,所有访问不了,但是确实被继承给了子类
class Base
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son :public Base
{
public:
int m_D;
};
Son s1;
//父类中私有成员属性,是被编译器隐藏了,所有访问不了,但是确实被继承给了子类
cout << sizeof(s1) << endl; //sizeof(s1)=16
#include<iostream>
using namespace std;
class Base
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son :public Base
{
public:
int m_D;
};
void test01()
{
Son s1;
//父类中非静态成员都会被子类继承下去
//父类中私有成员属性,是被编译器隐藏了,所有访问不了,但是确实被继承给了子类
cout << sizeof(s1) << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
四、继承中构造和析构顺序
子类继承父类后,创建子类的对象时,也会调用父类的构造函数
父类和子类构造,析构调用顺序:
先构造父类,再构造子类。析构顺序刚好相反。
——————————————
class Base
{
public:
Base()
{
cout << "调用基类构造函数" << endl;
}
~Base()
{
cout << "调用基类~析构函数" << endl;
}
};
class Son:public Base
{
public:
Son()
{
cout << "调用--子类构造函数" << endl;
}
~Son()
{
cout << "调用--子类~析构函数" << endl;
}
};
————————————————
五、继承同名成员处理方式
子类与父类出现同名成员,通过子类对象,访问子类或父类中同名数据
访问子类同名成员:直接访问
访问父类同名成员:加作用域访问
(1)、如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类的所有同名成员.此时想访问父类要加作用域
Son s;
cout << s.m_A << endl;
cout << s.Base::m_A << endl;
s.func();
s.Base::func(100);
(2)、如果子类没有,父类有,则可直接访问
s.Base::func(100);
可简化为:s.func(100); --->子类访问父类中的成员函数
如果子类有func(),父类有func(int)重载的,不可直接访问
#include<iostream>
using namespace std;
class Base
{
public:
Base()
{
m_A = 100;
}
//void func()
//{
// cout << "Base" << endl;
//}
void func(int)
{
cout << "Base func(int)" << endl;
}
public:
int m_A;
};
class Son :public Base
{
public:
Son()
{
m_A = 200;
}
//void func()
//{
// cout << "Son ." << endl;
//
public:
int m_A;
};
//同名成员变量
void test01()
{
Son s;
cout << s.m_A << endl;
cout << s.Base::m_A << endl;
}
//同名成员函数
void test02()
{
Son s;
//s.func();
//如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类的所有同名成员
//想访问父类要加作用域
s.Base::func(100);
s.func(100);
}
int main()
{
//test01();
test02();
system("pause");
return 0;
}
六、继承同名静态成员处理方式
继承同名静态成员处理 与 继承同名成员相同
(1)、访问静态成员变量
Son s;
1、通过对象访问静态成员变量
cout << s.m_A << endl; //子类
cout << s.Base::m_A << endl; //通过子类访问父类
2、通过类名访问静态成员变量
cout << Son::m_A << endl; //子类
cout << Son::Base::m_A << endl; //通过子类访问父类
cout << Base::m_A << endl; //父类
(Base::m_A 和 Son::Base::m_A 一样)
(2)、访问静态成员函数
Son s;
1、通过对象访问静态成员函数
s.func(); //子类
s.Base::func(); //通过子类访问父类
2、通过类名访问静态成员函数
Son::func(); //子类
Son::Base::func(); //通过子类访问父类
Base::func(); //父类
如果子类有func(),父类有func(int)重载的,不可直接访问
七、多继承语法
当父类中有同名成员出现时,必须加作用域才能区分。
c++实际开发不建议使用多继承
class Base1
{
public:
Base1()
{
m_A = 100;
}
public:
int m_A;
};
class Base2
{
public:
Base2()
{
m_A = 100;
}
public:
int m_A;
};
class Son :public Base1, public Base2
{
public:
Son()
{
m_C = 300;
m_D = 400;
}
public:
int m_C;
int m_D;
};
Son s;
cout << "sizeof(s)=" << sizeof(s) << endl; // 16
cout << "sizeof(Son)=" << sizeof(Son) << endl; //16
//父类中出现同名成员时,要加作用域才能区分
cout << "Base1 m_A=" << s.Base1::m_A << endl;
cout << "Base2 m_A=" << s.Base2::m_A << endl;
八、菱形继承
1、菱形继承
class A
class B:public A
class C:public A
class D:public B,public C
——————————————————————
class Animal
{
public:
int m_Age;
};
class Sheep :public Animal { };
class Tuo :public Animal { };
class SheepTuo :public Sheep, public Tuo { };
---------------------------------------------
SheepTuo st;
st.Sheep::m_Age = 10;
st.Tuo::m_Age = 7;
//菱形继承,父类拥有相同数据,必须加作用域才能区分
cout << "st.Sheep::m_Age =" << st.Sheep::m_Age << endl; //10
cout << "st.Tuo::m_Age =" << st.Tuo::m_Age << endl; //7
cout << st.m_Age << endl; //×,二义性
问题:那么此时,SheepTuo的m_Age 为10 还是 7 ?
解决:(使用虚继承)
————————————————————
2、引发问题
1、B继承A数据,C继承A数据,当D使用数据时,会产生二义性
2、D的数据继承了两份,数据重复了
——————————————————————
class Animal
{
public:
int m_Age;
};
//采用虚继承,此时Animal为虚基类
class Sheep :virtual public Animal { };
class Tuo :virtual public Animal { };
class SheepTuo :public Sheep, public Tuo { };
---------------------------------------------
SheepTuo st;
st.Sheep::m_Age = 10;
st.Tuo::m_Age = 7;
//菱形继承,父类拥有相同数据,必须加作用域才能区分
cout << "st.Sheep::m_Age =" << st.Sheep::m_Age << endl; //7
cout << "st.Tuo::m_Age =" << st.Tuo::m_Age << endl; //7
cout << st.m_Age << endl; //√,不会再报错
使用虚继承,Sheep和Tuo共享一份数据,
所以 st.Tuo::m_Age = 7;相当于把共享的再次都修改为7
——————————————————————
未使用虚继承时
使用虚继承时,vbptr 虚基类指针
Sheep 和 Tuo 保存的是 vbptr
#include<iostream>
using namespace std;
class Animal
{
public:
int m_Age;
};
//虚继承,Animal为虚基类
class Sheep :virtual public Animal { };
class Tuo :virtual public Animal { };
class SheepTuo :public Sheep, public Tuo { };
void test01()
{
SheepTuo st;
st.Sheep::m_Age = 10;
st.Tuo::m_Age = 7;
//菱形继承,父类拥有相同数据,必须加作用域才能区分
cout << "st.Sheep::m_Age =" << st.Sheep::m_Age << endl;
cout << "st.Tuo::m_Age =" << st.Tuo::m_Age << endl;
//菱形继承有两份数据,浪费资源
//使用虚继承,Sheep和Tuo共享一份数据
cout << st.m_Age << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
菱形继承值问题
A a;
a.m_A = 10;
B b;
b.m_A = 20;
C c;
c.m_A = 30;
D d;
d.B::m_A = 200;
d.C::m_A = 300;
cout << d.m_A << endl; //300
cout << a.m_A << endl; //10
cout << b.m_A << endl; //20
cout << c.m_A << endl; //30
#include<iostream>
using namespace std;
class A
{
public:
int m_A;
};
class B :virtual public A { };
class C :virtual public A { };
class D :public B,public C { };
void test01()
{
A a;
a.m_A = 10;
B b;
b.m_A = 20;
C c;
c.m_A = 30;
D d;
d.B::m_A = 200;
d.C::m_A = 300;
cout << d.m_A << endl; //300
cout << a.m_A << endl; //10
cout << b.m_A << endl; //20
cout << c.m_A << endl; //30
}
int main()
{
test01();
system("pause");
return 0;
}