一、构造功能
在一些重复内容中,往往我们会进行多次复制相同的变量或者函数在不同的类中,此时我们可以选择新建一个父类,把重复的内容写在父类内,把不同的内容在子类中单独写。然后使用子类继承父类的内容,以达到减少代码量的作用。
class BasePage
{
public:
void header()
{
cout << "首页、公开课、登录、注册...(公共头部)" << endl;
}
void footer()
{
cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
}
void left()
{
cout << "Java,Python,C++...(公共分类列表)" << endl;
}
};
class Java : public BasePage
{
public:
void content()
{
cout << "JAVA学科视频" << endl;
}
};
class Python : public BasePage
{
public:
void content()
{
cout << "Python学科视频" << endl;
}
};
class CPP : public BasePage
{
public:
void content()
{
cout << "C++学科视频" << endl;
}
};
void test01()
{
cout << "Java下载视频页面如下: " << endl;
Java ja;
ja.header();
ja.footer();
ja.left();
ja.content();
cout << "--------------------" << endl;
cout << "Python下载视频页面如下: " << endl;
Python py;
py.header();
py.footer();
py.left();
py.content();
cout << "--------------------" << endl;
cout << "C++下载视频页面如下: " << endl;
CPP cp;
cp.header();
cp.footer();
cp.left();
cp.content();
}
int main() {
test01();
system("pause");
return 0;
}
二、继承的格式
class A:public B
A类称为子类或派生类,B类称为父类或基类。派生类中的成员包含两大部分:一类是从基类继承过来的,一类是自己增加的成员,从基类继承过来的表现其共类,而新增的成员体现了其个性。
三、继承方式
1、公有继承:class son:public Base
①以下为父类
class Base1
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
②以下为子类,公有继承的子类可以访问父类的public和protected中的内容,不可以访问private
class son1:public Base1
{
public:
void func()
{
m_A;
m_B;
//m_C;
}
};
③以下为其他类,不是子类,只能访问public中的内容
void myclass()
{
son1 sn;
sn.m_A;
}
2、保护继承:class son:protected Base
①以下为父类
class Base2
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
②以下为子类,保护继承的子类可以访问父类的public和protected中的内容,不可以访问private,此时父类中的公共类型,到子类中变为保护权限。
class son2:protected Base2
{
public:
void func()
{
m_A;
m_B;
//m_C;
}
};
③以下为其他类,不是子类,进行保护继承后,父类中的公共类型,到子类中变为保护权限,所以不能访问
void myclass2()
{
son2 sn;
// sn.m_A;
}
3、私有继承:class son:private Base
①以下为父类
class Base3
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
②以下为子类,私有继承的子类可以访问父类的public和protected中的内容,不可以访问private,此时父类中的公共类型,到子类中变为私有权限。
class son3:private Base3
{
public:
void func()
{
m_A;
m_B;
//m_C;
}
};
③对第一次中的子类再次进行继承,因为第一次继承已经成私有,所以再次继承都不会被访问到。
class sonson3:public son3
{
public:
void func()
{
//m_A;
//m_B;
//m_C;
}
};
四、继承中的对象模型
问:从父类继承过来的成员,哪些输入子类对象中?
class Base
{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class son:public Base
{
public:
int m_D;
};
void test01()
{
cout << sizeof(son) << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
执行程序后输出:16,这说明父类的所有内容包括私有成员m_C也被继承了,只是被隐藏了访问不到。
五、继承中构造和析构顺序
问:父类和子类构造和析构顺序是谁先谁后?
class Base
{
public:
Base()
{
cout << "调用Base构造函数" << endl;
}
~Base()
{
cout << "调用Base析构函数" << endl;
}
};
class Son:public Base
{
public:
Son()
{
cout << "调用Son构造函数" << endl;
}
~Son()
{
cout << "调用Son构造函数" << endl;
}
};
void test01()
{
Son s;
}
以下为编译结果,继承中,先调用父类的构造函数,再调用子类的构造函数,析构函数相反。所有构造执行完毕之后才会执行析构函数。
六、继承同名成员处理方式
1、访问子类同名成员,直接访问即可
访问父类同名成员,需要加作用域
class Base
{
public:
Base()
{
m_A=100;
}
void func()
{
cout << "base func()调用" << endl;
}
void func(int a)
{
cout << "base func(int a)调用" << endl;
}
public:
int m_A;
};
class Son:public Base
{
public:
Son()
{
m_A = 200;
}
void func()
{
cout << "son func()调用" << endl;
}
public:
int m_A;
};
void test01()
{
Son s;
cout << s.m_A << endl;
cout << s.Base::m_A << endl;
s.func();
s.Base::func();
s.Base::func(10);
}
2、输出结果
3、总结
①子类对象可以直接访问子类中的同名成员
②子类对象加作用域可以访问到父类同名成员
③当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数,如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域
七、静态同名静态成员处理方式
1、静态成员和非静态成员出现同名,处理方式一致
访问子类同名成员,直接访问即可;访问父类同名成员,需要加作用域。
2、同名静态成员处理方式有两种访问方式,通过对象访问和通过类名访问
void test01()
{
cout << "通过对象访问: " << endl;
Son s;
s.func();
s.Base::func();
cout << "通过类名访问: " << endl;
Son::func();
Son::Base::func();
//出现同名,子类会隐藏掉父类中所有同名成员函数,需要加作作用域访问
Son::Base::func(100);
}
八、多继承语法
C++允许一个类继承多个类
语法:class 子类:继承方式 父类1,继承方式 父类2 .......
多继承可能会引发父类中有同名成员出现,需要加作用域区分
class Base1
{
public:
Base1()
{
m_A=100;
}
public:
int m_A;
};
class Base2
{
public:
Base2()
{
m_A=200;
}
public:
int m_A;
};
class Son:public Base2,public Base1
{
public:
};
void test01()
{
Son s;
//cout << s.m_A << endl; //出现重复,报错,需要加作用域
cout << s.Base1::m_A << endl;
cout << s.Base2::m_A << endl;
}
九、菱形继承
1、两个子类继承同一个基类,又有某个类同时继承两个子类,这种继承称为菱形继承,或者钻石继承。
2、羊继承了动物的数据,驼同样继承了动物的数据,当草泥马使用数据时,就会产生二义性。草泥马继承自动物的数据继承了两份,其实我们应该清楚,这份数据我们只需要一份就可以。
class Animial
{
public:
int m_Age;
};
class Sheep: public Animial{};
class Tuo: public Animial{};
class SheepTuo:public Sheep,public Tuo{};
void test01()
{
SheepTuo st;
st.Sheep::m_Age = 100;
st.Tuo::m_Age = 200;
cout << st.Sheep::m_Age << endl;
cout << st.Tuo::m_Age << endl;
//cout << st.m_Age << endl; //报错
}
此时输出的数值为100 200,最后的报错,注释掉。
class Animial
{
public:
int m_Age;
};
class Sheep:virtual public Animial{};
class Tuo:virtual public Animial{};
class SheepTuo:public Sheep,public Tuo{};
void test01()
{
SheepTuo st;
st.Sheep::m_Age = 100;
st.Tuo::m_Age = 200;
cout << st.Sheep::m_Age << endl;
cout << st.Tuo::m_Age << endl;
cout << st.m_Age << endl;
}
假如virtual关键字后,变为虚继承,输出200 200 200,st.m_Age也不会报错
3、菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义,利用虚继承可以解决菱形继承问题。