继承
1.继承是什么?
在 C++ 中,继承(Inheritance) 是面向对象编程(OOP)的核心特性之一,允许一个类从另一个类派生,继承其属性(成员变量)和行为(成员函数),从而实现代码复用和多态性。子类——派生类,父类——基类
基本语法
class 父类名 {
public:
int a;
void show() {
std::cout << "This is base class" << std::endl;
}
};
class 子类名 : 继承方式 父类名 {
public:
int b;
void display() {
std::cout << "This is derived class" << std::endl;
}
};
三种继承方式
继承方式语法示例父类的 public 成员在子类中protected 成员private 成员public 继承class B : public A保持 public保持 protected不可访问protected 继承class B : protected A变成 protected保持 protected不可访问private 继承class B : private A变成 private变成 private不可访问
1)public继承
#include
using namespace std;
class base1
{
public:
int m_a;
protected:
int m_b;
private:
int m_c;
};
class son:public base1
{
public:
void func()
{
m_a;//父类中的公共权限成员 到子类中依然是公共权限
m_b;//父类中的保护权限成员 到子类中依然是保护权限
//m_c,父类中的私有权限成员 到子类中依然是私有权限,访问不到
}
};
void test_01()
{
son s1;
s1.m_a=12;
cout< s1.func(); } int main() { test_01(); return 0; } public继承在子类里面,可以对父类public,protected变量进行访问修改 在子类外,仅能对public修改,而protected不行,如上代码所示 2)protected继承 #include using namespace std; class base1 { public: int m_a; protected: int m_b; private: int m_c; }; class son:protected base1 { public: void func() { m_a;//父类中的公共权限成员 到子类中变成保护权限 m_b;//父类中的保护权限成员 到子类中变成保护权限 //m_c,父类中的私有权限成员 到子类中依然是私有权限,访问不到 } }; void test_01() { son s1; //s1.m_a=12;已变为protected不可访问编辑 //s1.m_b=20;protected不可访问编辑 } int main() { return 0; } protected继承在子类里面,可以对父类public(变为protected类型),protected变量进行访问修改 在子类外,对public,protected都不行(都已是protected类型),如上代码所示 3)private继承 #include using namespace std; class base1 { public: int m_a; protected: int m_b; private: int m_c; }; class son:private base1 { public: void func() { m_a=10;//父类中的公共权限成员 到子类中变成私有权限 m_b=10;//父类中的保护权限成员 到子类中变成私有权限 //m_c,父类中的私有权限成员 到子类中依然是私有权限,访问不到 } }; class gdson:public son { public: void func() { //m_a访问不到,已经变为私有 } }; int main() { return 0; } private继承在子类里面,可以对父类public,protected变量进行访问修改 在子类外,对public,protected都不行(都已是private类型) 在对私有继承再继承时,都不能访问并编辑(都已是private类型),如上代码所示 2.继承中构造与析构顺序 在我们学习了三种继承方式,你是否会有疑问?——类中有构造与析构函数,那么继承中他们顺序是怎么样的,这一下小节我们就来探讨一下 #include using namespace std; class base { public: base() { cout<<"父类构造函数"< } ~base() { cout<<"父类析构函数"< } }; class son:public base { public: son() { cout<<"子类构造函数"< } ~son() { cout<<"子类析构函数"< } }; void test_01() { son s1; } int main() { test_01(); return 0; } 输出结果如下: 我们可以看到顺序是——父->子->子->父 3.继承同名成员处理方式 1)同名成员变量处理 在遇到父子类都有相同名的变量时,该如何正确访问呢,如下代码所示: class base { public: base() { m_a=100; } int m_a; }; class son:private base { public: son() { m_a=200; } int m_a; }; 我们先进行简单测试一下: #include using namespace std; class base { public: base() { m_a=100; } int m_a; }; class son:public base { public: son() { m_a=200; } int m_a; }; void test_01() { son s1; cout< } int main() { test_01(); return 0; } 最后输出结果是200,“那我想访问父类的m_a该怎么做呢?”,其实我们只要加一作用域就可以达到我们想要的效果了 cout<<"子类的数据"< cout<<"父类的数据"< 这样就ok了啊 2)同名成员函数处理 函数处理其实和成员变量处理方式一样,加个作用域就可以 son s1; s1.func();//子类函数调用 s1.base::func();//父类函数调用 但是这里要介绍一个容易出现问题的地方: class base { public: base() { m_a=100; } void func() { cout<<"父类的函数调用"< } void func(int a) { cout<<"父类的函数调用(int a)"< } int m_a; }; class son:public base { public: son() { m_a=200; } void func() { cout<<"子类的函数调用"< } int m_a; }; void test_01() { son s1; s1.func(100); } 在父类里面我们对func()函数进行了一个有参重载 但是在调用s1.func(100)会出现报错 为什么加了参数还不能定位到父类函数呢?——其实原因就在于子类创建后,会屏蔽一切所有父类同名函数,切记是同名,所以解决方法,再加一个作用域就好啦 son s1; s1.base::func(100); 小总结 子类可以直接访问,子类中同名成员子类访问父类同名成员,需加上作用域 4.继承同名静态成员处理方法 1)通过对象访问 就是简单的添加作用域访问 #include using namespace std; class base { public: static int m_a; }; int base:: m_a=100; class son:public base { public: static int m_a; }; int son:: m_a=200; void test_01() { son s1; cout< cout< } int main() { test_01(); return 0; } 2)通过类名访问 void test_01() { //通过类名访问 cout< cout< //通过 son 继承的 base 路径访问 cout< } 这就是static特殊的地方,创建了就一直存在,所有在作用域内的代码可以访问同一块地址 小总结 主要就是static可以用类访问,但切记变量类内声明,类外初始化函数同样的方法可以访问,函数可在直接类内定义 5.菱形继承 如下图所示,在B,C继承A之后,我们D多继承B,C之后,那么我们对于m_a该如何访问并修改呢? 首先如下代码所示: #include using namespace std; class A { public: int m_a; }; class B:public A {}; class C:public A {}; class D:public B,public C {}; void test_01() { D d1; d1.B::m_a=100; d1.C::m_a=300; cout<<"B的a:"< cout<<"C的a:"< } int main() { test_01(); return 0; } 输出结果如下: 这里其实和第三节方法是一样的,是对同名变量的操作 但是,这里其实是有问题,这样两个变量都是对A的继承,就会造成资源浪费,那我们怎么解决呢? 这里就引出一个新的概念——虚继承 class B:virtual public A {}; class C:virtual public A {}; 我们只需将B,C加上virtual,就可以解决问题 这时候的完整代码: #include 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 test_01() { D d1; d1.B::m_a=100; d1.C::m_a=300; cout<<"B的a:"< cout<<"C的a:"< } int main() { test_01(); return 0; } 输出结果如下所示: 可以发现,这时候m_a已经是一个变量了,不会造成出现两个这种情况了 6.总结 这就是我对继承的理解啦!从语法到实际使用,其实并不难,只要多写几次自然就熟悉了。下一篇我会记录下“多态”的使用,尤其是虚函数和虚继承的细节,欢迎继续关注!