继承
继承的基本语法
继承的好处:减少重复代码
语法: class 子类 : 继承方式 父类
class A : public B;
子类,也被称为“派生类”
父类,也被称为“基类”
派生类中的成员,包含两大部分:
- 一类是从基类继承过来的,一类是自己增加的成员。
- 从基类继承过来的表现了其共性,而新增的成员体现了其个性
#include <iostream>
using namespace std;
// 继承的基本语法
// 公共页面
class BasePage
{
public:
void header()
{
cout<<"首页、公开课、登录、注册......"<<endl;
}
void footer()
{
cout<<"帮助中心、交流合作......"<<endl;
}
void left()
{
cout<<"Java、Python、C/C++......"<<endl;
}
};
// Java 页面
class Java : public BasePage
{
public:
void content()
{
cout<<"Java学科视频"<<endl;
}
};
// Python 页面
class Python : public BasePage
{
public:
void content()
{
cout<<"Python学科视频"<<endl;
}
};
void test01()
{
cout<<"Java视频页面如下......"<<endl;
Java jv;
jv.header();
jv.footer();
jv.left();
jv.content();
cout<<endl;
cout<<"Python视频页面如下......"<<endl;
Python py;
py.header();
py.footer();
py.left();
py.content();
}
int main()
{
test01();
system("pause");
return 0;
}
运行结果:
Java视频页面如下......
首页、公开课、登录、注册......
帮助中心、交流合作......
Java、Python、C/C++......
Java学科视频
Python视频页面如下......
首页、公开课、登录、注册......
帮助中心、交流合作......
Java、Python、C/C++......
Python学科视频
请按任意键继续. . .
继承方式
公共继承、保护继承。私有继承
继承中的对象模型
父类中所有非静态成员属性都会被子类继承下去
父类中私有成员属性,是被编译器给隐藏了,因此是访问不到的,但是确实被继承下去了
查看对象模型 ( CL / D1)
如何查看C++ class的对象模型
vs2015开发人员命令提示工具 查看C++类对象模型
#include <iostream>
using namespace std;
// 继承中的对象模型
class Base
{
public:
int m_A;
protected:
int m_B;
public:
int m_C;
};
class Son:public Base
{
public:
int m_D;
};
void test()
{
cout<<sizeof(Son)<<endl;
}
int main()
{
test();
system("pause");
return 0;
}
运行结果:
16
请按任意键继续. . .
继承中构造和析构顺序
问题:父类和子类的构造和析构顺序是谁先谁后?
继承同名成员的处理方式
当子类与父类中都出现了同名的成员…
- 访问子类同名成员,直接访问即可
- 访问父类同名成员,需要加作用域
- 如果父类的同名成员是有参函数,而子类的同名成员是无参函数,只要同名,都必须加作用域
继承同名静态成员处理方式
同上,加作用域
#include <iostream>
using namespace std;
// 继承的构造和析构顺序
// 成员同名
class Base
{
public:
Base()
{
m_A = 100;
cout<<"Base的构造函数"<<endl;
}
~Base()
{
cout<<"Base的析构函数"<<endl;
}
void func()
{
cout<<"Base-->func函数"<<endl;
}
int m_A;
static int m_B;
};
int Base::m_B = 111;
class Son: public Base
{
public:
Son()
{
m_A = 200;
cout<<"Son的构造函数"<<endl;
}
~Son()
{
cout<<"Son的析构函数"<<endl;
}
void func()
{
cout<<"Son-->func函数"<<endl;
}
int m_A;
static int m_B;
};
int Son::m_B = 222;
void test()
{
Son s;
cout<<"Son --> m_A "<<s.m_A<<endl;
cout<<"Base --> m_A "<<s.Base::m_A<<endl;
s.func();
s.Base::func();
cout<<"Son --> m_B "<<s.m_B<<endl;
cout<<"Base --> m_B "<<s.Base::m_B<<endl;
cout<<"-- 通过类名访问 static 成员对象 --"<<endl;
cout<<"Son --> m_B "<<Son::m_B<<endl;
cout<<"Base --> m_B "<<Son::Base::m_B<<endl;
}
int main()
{
test();
system("pause");
return 0;
}
运行结果:
Base的构造函数
Son的构造函数
Son --> m_A 200
Base --> m_A 100
Son-->func函数
Base-->func函数
Son --> m_B 222
Base --> m_B 111
-- 通过类名访问 static 成员对象 --
Son --> m_B 222
Base --> m_B 111
Son的析构函数
Base的析构函数
请按任意键继续. . .
多继承语法
C++ 允许一个类继承多个类 (一个父亲多个儿子)
语法:
class 子类 : 继承方式 父类1, 继承方式 父类2 ...
多继承可能会引发父类中有同名成员出现,需要加作用域区分,实际开发中不建议多继承
#include <iostream>
using namespace std;
// 多继承语法
class Base1
{
public:
Base1()
{
m_A = 11;
}
int m_A;
};
class Base2
{
public:
Base2()
{
m_A = 22;
}
int m_A;
};
class Son:public Base1, public Base2
{
public:
Son()
{
m_C = 33;
}
int m_C;
};
void test()
{
Son s;
cout<<"Son占用内存:"<<sizeof(s)<<endl;
cout<<"Base1-->m_A: "<<s.Base1::m_A<<endl;
cout<<"Base2-->m_A: "<<s.Base2::m_A<<endl;
}
int main()
{
test();
system("pause");
return 0;
}
运行结果:
Son占用内存:12
Base1-->m_A: 11
Base2-->m_A: 22
请按任意键继续. . .
菱形继承
概念:
- 两个派生类继承同一个基类
- 又有某个类同时继承着两个派生类
这种继承被称为菱形继承,或者钻石继承
问题:解决二义性
在继承之前,加 virtual ,虚继承
用 VS 的开发者命令行查看,会了解这个 vbptr , virtual base pointer
偏移量的知识点:操作系统,汇编
#include <iostream>
using namespace std;
// 菱形继承
class Animal
{
public:
int m_Age;
};
class Sheep: virtual public Animal{};
class Tuo:virtual public Animal{};
class SheepTuo:public Sheep, public Tuo{};
void test()
{
SheepTuo st;
st.Sheep::m_Age = 21;
st.Tuo::m_Age = 27;
cout<<"st.Sheep::m_Age = "<<st.Sheep::m_Age<<endl;
cout<<"st.Tuo::m_Age = "<<st.Tuo::m_Age<<endl;
cout<<"st.m_Age = "<<st.m_Age<<endl;
}
int main()
{
test();
system("pause");
return 0;
}
运行结果:
st.Sheep::m_Age = 27
st.Tuo::m_Age = 27
st.m_Age = 27
请按任意键继续. . .