【C++】面试常考的三大特性——封装、继承、多态

本文详细介绍了C++的三大特性——封装、继承和多态。封装通过隐藏对象的属性和实现细节,提供对外接口。继承允许代码复用,派生类可以从基类继承并扩展功能。多态则是通过虚函数实现,使得不同对象执行同一行为时产生不同形态。文章通过实例解释了这些概念,并讨论了继承中的作用域、菱形继承和抽象类等高级主题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、封装

1.什么是封装

封装是将数据与方法进行结合,隐藏对象的部分属性和实现细节,对外开放一些接口,通过这些接口约束,类外可以合理的访问类内的属性

2.封装的作用

封装可以让数据隐藏
让类外合理访问类内的数据

3.为什么需要封装

将一个对象的属性和行为结合在一起更符合人们对事务的认知,通过访问限定符将部分功能开放出来域其他对象进行交互,外部用户是不需要知道具体的实现细节的,即使知道了,也只会增加使用和维护的难度,让事情变得复杂

4.举例

乘火车

  • 售票系统:负责售票,用户凭票进入,对号入座
  • 工作人员:售票、咨询、安检、保全、卫生等
  • 火车:带用户到目的地
    例如我们坐火车买票,我们只需要知道票在哪买的,去哪里可以乘车,不需要去了解火车的构造,购票系统的内部操作,但是火车站不能不管理,它需要“封”起来,只提供部分通道供乘客进入,不能就直接暴露出来,如果从任何地方都能上车,那整个流程就乱套了

二、继承

1.什么是继承

继承机制是面向对象程序设计代码可以复用的重要手段,它允许程序在保持原有类特性的基础上进行扩展,增加功能,产生的新类称为派生类

class Person
{
   
public: 
	void Print()
	{
   
	cout << "name:" << _name << endl;
	cout << "age:" << _age << endl;
	}
protected:
	string _name = "limengru";//姓名
	int _age = 21; //年龄
};
//学生类公有继承了Person类,person的成员函数和成员变量都会变成子类的一部分
class Student : public Person
{
   
protected:
	int _stuid;//学号
};
 

1.1 继承定义格式

在这里插入图片描述

1.2继承关系和访问限定符

在这里插入图片描述

1.3.继承基类成员访问方式的变化

类成员/继承方式 public继承 protected继承 private继承
基类的public成员 派生类的public成员 派生类的protected成员 派生类的private成员
基类的protected成员 派生类protected成员 派生类的protected成员 派生类的private成员
基类的private成员 在派生类中不可见 在派生类中不可见 在派生类中不可见

2.基类和派生类对象的赋值转换

  • 1.派生类对象可以赋值给基类对象/基类指针/基类的引用(切片或切割,指把派生类中父类的那部分切割下来,赋值过去)
  • 2.基类对象不能赋值给派生类的对象
  • 3.基类的指针可以通过强制类型转换赋值给派生类的指针

在这里插入图片描述

3.继承中的作用域

  • 1.在继承体系中基类和子类都有独立的作用域
  • 2.子类和父类拥有同名成员 ,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,也叫重定义
  • 3.注意:如果是成员函数的隐藏,只需要函数名相同就构成隐藏
  • 4.所以实际中在继承体系里最好不要定义同名的成员

举例1

class Person
{
   
public: 
	void Print()
	{
   
	cout << "name:" << _name << endl;
	cout << "age:" << _age << endl;
	}
protected:
	string _name = "limengru";//姓名
	int _age = 21; //年龄
};
//学生类公有继承了Person类,person的成员函数和成员变量都会变成子类的一部分
class Student : public Person
{
   
protected:
	int _stuid;//学号
	string _name = "dameinv";
};

可以看到上面的代码虽然没有错误,但是基类和子类的_name构成了隐藏关系,非常容易混淆

举例2

class A
{
   
public:
	void fun()
	{
   
		cout << "fun()" << endl;
	}
};
class B : public A
{
   
public:
	void fun(int i)
	{
   
		A::fun();
		cout << "fun(int i)" << endl;
	}
};

上面这个例子,A和B中的fun函数不构成重载,因为不在同一个作用域
但是这两个fun构成隐藏,因为成员函数满足函数名相同就构成隐藏

4.派生类的默认成员函数

在之前的学习中,我们知道类会有六个默认的成员函数,即使我们不写,编译器也会为我们自动生成一个,那么派生类中这几个“特殊”的函数是怎么生成的呢?

  • 1.派生类的构造函数必须调用基类的构造函数初始化基类那一部分的成员,如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用
  • 2.派生类的拷贝构造函数必须调用基类的拷贝构造函数完成基类的拷贝和初始化
  • 3.派生类的operator=必须调用基类的operatr=完成基类的赋值
  • 4.派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员,因为这样才能保证派生类对象先清理派生类成员,再清理基类成员函数的顺序
  • 5.派生类对象初始化先调用基类的构造函数,再调用派生类的构造函数
  • 6.派生类的对象的清理先调用派生类的析构函数,再调用基类的析构函数
    在这里插入图片描述

5.继承和友元

友元关系是不能继承的,基类的友元函数不能访问子类的私有和保护成员

#include <iostream>
#include <string>
using namespace std;
class Student;
class Person
{
   
public:
	friend void Display(const Person& p, const Student& s);
protected:
	string _name;
};
class Student : public Person
{
   
protected:
	int _stuNo;
};
void Display(const Person& p, const Student& s)
{
   
	cout << p._name << endl;
	cout << s._stuNo << endl;
}

正如上面的代码,在编译后会给我们报出如下图的错误,代表即使是基类的友元,也不能访问子类的私有和保护成员
在这里插入图片描述

6.继承和静态成员

基类定义了static静态成员,则整个继承体系里面只有一个这样的成员,无论派生出多少个子类,都只有一个static成员实例

1.举例

#include <iostream>
#include <string>
using namespace std;
class Student;
class Person
{
   
public:
	Person() {
    ++_count; }
protected:
	string _name;
public:
	static int _count;
};
int Person::_count = 0;//设置_count的值为0
class Student : public Person
{
   
protected:
	int _stuNo;
};	
class Graduate : public Student
{
   
protected
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风铃奈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值