继承基础
继承得好处:减少重复代码
语法:
class 子类 : 继承方式 父类
子类也称为:派生类
父类也称为:基类
eg:
#include
using namespace std;
//公共部分
class BasePage
{
public:
void test()
{
cout << "java,C++,Python" << endl;
}
};
//继承
class java : public BasePage
{
public:
void content()
{
cout << "java学科视频" << endl;
}
};
int main()
{
java a;
a.test();
a.content();
}
继承方式
1.公共继承
2.保护继承
3.私有继承
原理图:
继承中的对象模型
问题:从父类继承过来的成员,哪些属于子类对象中?
案例分析:
#include
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;
};
int main()
{
son a;
cout << sizeof(a) << endl;
}
执行结果:
16
结论:
父类中所有非静态成员属性都会被子类继承下去。
父类中的私有成员属性是被编译器给隐藏了,因此是访问不到的,但确实被继承下去了。
继承中构造和析构顺序
子类继承父类后,当创建子类对象,也会调用父类的构造函数
问题:
父类和子类的构造和析构顺序是谁先谁后?
实例:
#include
using namespace std;
class base
{
public:
base()
{
cout << "base的构造函数" << endl;
}
~base()
{
cout << "base的析构函数" << endl;
}
};
class son:private base
{
public:
son()
{
cout << "son的构造函数" << endl;
}
~son()
{
cout << "son的析构函数" << endl;
}
public:
int m_d;
};
int main()
{
son a;
}
执行结果:
结论:
继承中的构造和析构顺序如下:
先构造父类,再构造子类,
先析构子类,再析构父类。
继承同名成员处理方式
问题:当子类与父类出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据呢?
1.访问子类同名成员,直接访问即可
2.访问父类同名成员,需要加作用域
eg:
1.同名成员属性
#include
using namespace std;
class base
{
public:
int m_a;
base()
{
m_a = 100;
}
};
class son :public base
{
public:
int m_b;
son()
{
m_a = 200;
}
};
int main()
{
son a;
cout << a.m_a << endl;//访问子类中的成员
cout << a.base::m_a << endl;//访问父类中的成员
}
2.同名成员函数
#include
using namespace std;
class base
{
public:
void func()
{
cout << "调用base下的func函数" << endl;
}
};
class son :public base
{
public:
void func()
{
cout << "调用son下的func函数" << endl;
}
};
int main()
{
son a;
a.func();//访问子类中的成员
a.base::func();//访问父类中的成员
}
注意事项:
如果子类中出现了和父类同名的成员函数,子类的同名函数成员回隐藏掉父类中所有同名成员函数
如果想访问到父类中被隐藏的同名成员函数,需要加作用域。
继承同名静态成员处理方式
问题:继承中同名的静态成员在子类对象上如何进行访问?
静态成员和非静态成员出现同名,处理方式一致
1.访问子类同名成员,直接访问即可
2.访问父类同名成员,需要加作用域
eg:
1.同名的静态成员属性
#include
using namespace std;
class base
{
public:
static int m_a;
};
int base::m_a = 200;
class son:public base
{
public:
static int m_a;
};
int son::m_a = 100;
int main()
{
son a;
//1.通过对象访问
cout << "son下的m_a = " << a.m_a << endl;
cout << "base下的m_a = " << a.base::m_a << endl;
//2.通过类名访问
cout << "son下的m_a = " << son::m_a << endl;
cout<<"base下的m_a = "<<son::base::m_a<<endl;
//解析:第一个::代表通过类名的方式访问 第二个::代表访问父类作用域下的m_a
}
2.同名的静态成员函数
#include
using namespace std;
class base
{
public:
static int m_a;
static void func()
{
cout << "base" << endl;
}
};
int base::m_a = 200;
class son:public base
{
public:
static int m_a;
static void func()
{
cout << "son" << endl;
}
};
int son::m_a = 100;
int main()
{
son a;
//1.通过对象访问
a.func();
a.base::func();
//2.通过类名访问
son::func();
son::base::func();
//解析:第一个::代表通过类名的方式访问 第二个::代表访问父类作用域下的func()
}
注意事项:
如果子类中出现了和父类同名的静态成员函数,子类的同名函数成员回隐藏掉父类中所有同名成员函数
如果想访问到父类中被隐藏的同名静态成员函数,需要加作用域。
多继承语法
C++允许一个类继承多个类
语法:
class 子类 : 继承方式 父类1, 继承方式 父类2...
多继承可能会引发父类中有同名成员函数出现,需要加作用域区分
注意:
C++实际开发中不建议用多继承
#include
using namespace std;
class base1
{
public:
int m_a;
base1()
{
m_a = 100;
}
};
class base2
{
public:
int m_b;
base2()
{
m_b = 100;
}
};
class son: public base1,public base2
{
public:
int m_c;
};
菱形继承
菱形继承概念:
两个派生类继承同一个基类
又有某个类同时继承两个派生类
这种继承称为菱形继承,或者钻石继承
图示:
问题:
1.两个派生类都会有基类的数据,会产生二义性
2.子类会继承两份来自动物的数据,其实并不需要
解决方法:
利用虚继承可以解决菱形继承的问题
即:在继承之前加上关键字virtual 变为虚继承
eg:
#include
using namespace std;
class A
{
public:
int m_age;
};
class B:virtual public A{
};
class C :virtual public A {
};
class D : public B, public C{
};
int main()
{
D a;
a.A::m_age = 1;
a.B::m_age = 2;
a.C::m_age = 3;
cout << a.m_age << endl;
}