继承
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<iostream>
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.m_a<<endl;
s1.func();
}
int main()
{
test_01();
return 0;
}
public继承在子类里面,可以对父类public,protected变量进行访问修改在
子类外,仅能对public修改,而protected不行,如上代码所示
2)protected继承
#include<iostream>
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<iostream>
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<iostream>
using namespace std;
class base
{
public:
base()
{
cout<<"父类构造函数"<<endl;
}
~base()
{
cout<<"父类析构函数"<<endl;
}
};
class son:public base
{
public:
son()
{
cout<<"子类构造函数"<<endl;
}
~son()
{
cout<<"子类析构函数"<<endl;
}
};
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<iostream>
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<<s1.m_a<<endl;
}
int main()
{
test_01();
return 0;
}
最后输出结果是
200,“那我想访问父类的m_a该怎么做呢?”,其实我们只要加一作用域就可以达到我们想要的效果了cout<<"子类的数据"<<s1.m_a<<endl; cout<<"父类的数据"<<s1.base::m_a<<endl;这样就ok了啊
2)同名成员函数处理
函数处理其实和成员变量处理方式
一样,加个作用域就可以son s1; s1.func();//子类函数调用 s1.base::func();//父类函数调用但是这里要介绍一个容易出现问题的地方:
class base
{
public:
base()
{
m_a=100;
}
void func()
{
cout<<"父类的函数调用"<<endl;
}
void func(int a)
{
cout<<"父类的函数调用(int a)"<<endl;
}
int m_a;
};
class son:public base
{
public:
son()
{
m_a=200;
}
void func()
{
cout<<"子类的函数调用"<<endl;
}
int m_a;
};
void test_01()
{
son s1;
s1.func(100);
}
在父类里面我们对
func()函数进行了一个有参重载但是在调用
s1.func(100)会出现报错为什么加了参数还不能定位到父类函数呢?——其实原因就在于
子类创建后,会屏蔽一切所有父类同名函数,切记是同名,所以解决方法,再加一个作用域就好啦son s1; s1.base::func(100);
小总结
- 子类可以直接访问,子类中同名成员
- 子类访问父类同名成员,需加上作用域
4.继承同名静态成员处理方法
1)通过对象访问
就是简单的添加作用域访问
#include<iostream>
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<<s1.m_a<<endl;
cout<<s1.base::m_a<<endl;
}
int main()
{
test_01();
return 0;
}
2)通过类名访问
void test_01() { //通过类名访问 cout<<son::m_a<<endl; cout<<base::m_a<<endl; //通过 son 继承的 base 路径访问 cout<<son::base::m_a<<endl; }这就是
static特殊的地方,创建了就一直存在,所有在作用域内的代码可以访问同一块地址
小总结
- 主要就是static可以用类访问,但切记
变量类内声明,类外初始化 - 函数同样的方法可以访问,函数可在直接类内定义
5.菱形继承
如下图所示,在B,C继承A之后,我们D
多继承B,C之后,那么我们对于m_a该如何访问并修改呢?
首先如下代码所示:
#include<iostream>
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:"<<d1.B::m_a<<endl;
cout<<"C的a:"<<d1.C::m_a<<endl;
}
int main()
{
test_01();
return 0;
}
输出结果如下:

这里其实和第三节方法是一样的,是对同名变量的操作
但是,这里其实是有问题,这样两个变量都是对A的继承,就会造成资源浪费,那我们怎么解决呢?
这里就引出一个新的概念——虚继承
class B:virtual public A {}; class C:virtual public A {};我们只需将B,C加上
virtual,就可以解决问题
这时候的完整代码:
#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 test_01()
{
D d1;
d1.B::m_a=100;
d1.C::m_a=300;
cout<<"B的a:"<<d1.B::m_a<<endl;
cout<<"C的a:"<<d1.C::m_a<<endl;
}
int main()
{
test_01();
return 0;
}
输出结果如下所示:

可以发现,这时候m_a已经是一个变量了,不会造成出现两个这种情况了
6.总结
这就是我对继承的理解啦!从语法到实际使用,其实并不难,只要多写几次自然就熟悉了。下一篇我会记录下“多态”的使用,尤其是虚函数和虚继承的细节,欢迎继续关注!

497

被折叠的 条评论
为什么被折叠?



