C++面向对象的常见面试题目(一)

1. 面向对象的三大特征

(1)封装:隐藏对象的内部状态,只暴露必要的接口。

#include <iostream>
#include <string>// 定义一个简单的类 Person
class Person {
private: // 私有成员,外部不可直接访问std::string name;int age;public: // 公共方法,外部可以访问// 构造函数,用于初始化对象Person(std::string n, int a) {name = n;age = a;}// 公共方法,用于设置年龄void setAge(int a) {if (a > 0 && a < 150) { // 简单的年龄验证age = a;} else {std::cout << "Invalid age!" << std::endl;}}// 公共方法,用于获取姓名std::string getName() {return name;}// 公共方法,用于获取年龄int getAge() {return age;}
};int main() {// 创建 Person 对象Person p1("Alice", 30);// 尝试直接访问私有成员(编译错误)// std::cout << p1.name << std::endl;// 使用公共方法设置年龄p1.setAge(35);// 使用公共方法获取姓名和年龄std::cout << "Name: " << p1.getName() << ", Age: " << p1.getAge() << std::endl;return 0;
}

(2)继承:无需修改原有类的情况下对功能实现拓展

#include <iostream>
#include <string>// 定义一个基类 Animal
class Animal {
protected: // 受保护的成员,子类可以访问std::string name;public:// 构造函数,初始化 Animal 的名称Animal(std::string n) : name(n) {}// 公共方法,用于输出 Animal 的声音void makeSound() const {std::cout << "Animal " << name << " makes a sound" << std::endl;}
};// 定义一个派生类 Dog,继承自 Animal
class Dog : public Animal {
private:std::string breed;public:// 构造函数,初始化 Dog 的名称和品种Dog(std::string n, std::string b) : Animal(n), breed(b) {}// 重写父类的 makeSound 方法void makeSound() const {std::cout << "Dog " << name << " barks" << std::endl;}// 新的方法,用于输出 Dog 的品种void showBreed() const {std::cout << "Dog " << name << " is of breed " << breed << std::endl;}
};int main() {// 创建 Animal 对象Animal a("Generic");// 调用 Animal 的方法a.makeSound();// 创建 Dog 对象Dog d("Buddy", "Labrador");// 调用 Dog 的方法d.makeSound();d.showBreed();// 使用基类指针指向派生类对象,演示多态Animal* animalPtr = &d;animalPtr->makeSound(); // 调用的是 Dog 的 makeSound 方法return 0;
}

(3)多态:同一个函数名在不同对象中有不同的行为。通过时下接口重用增强可拓展性

多态分为2类,静态多态和动态多态。

静态多态:又称编译时多态。通过函数重载和运算符重载实现。

动态多态:又称运行时多态,通过虚函数和继承实现。

虚函数:在基类中声明函数为虚函数,派生类可以覆盖这些虚函数,从而实现不同的行为。在运行时,根据对象的实际类型决定调用哪个版本的函数,这种机制称为动态绑定或后期绑定。

// 静态多态
#include <iostream>class MathTool {
public:// 计算整数平方int calculateSquare(int number) {return number * number;}// 计算浮点数平方double calculateSquare(double number) {return number * number;}
};int main() {MathTool tool;// 静态多态示例:根据参数类型自动选择合适的方法std::cout << "整数5的平方是: " << tool.calculateSquare(5) << std::endl;      // 调用整数版本std::cout << "浮点数2.5的平方是: " << tool.calculateSquare(2.5) << std::endl; // 调用浮点数版本return 0;
}// 动态多态
#include <iostream>// 基类,含有虚函数
class Animal {
public:virtual ~Animal() {} // 虚析构函数,确保通过基类指针删除派生类对象时能正确调用派生类的析构函数virtual void makeSound() {std::cout << "Some animal makes a sound." << std::endl;}
};// 派生类1
class Dog : public Animal {
public:void makeSound() override {std::cout << "Dog barks." << std::endl;}
};// 派生类2
class Cat : public Animal {
public:void makeSound() override {std::cout << "Cat meows." << std::endl;}
};int main() {Animal* animalPtr; // 基类指针// 动态分配内存给派生类对象animalPtr = new Dog();animalPtr->makeSound(); // 运行时动态决定调用Dog的makeSound()animalPtr = new Cat();animalPtr->makeSound(); // 运行时动态决定调用Cat的makeSound()delete animalPtr; // 由于基类析构函数为虚函数,可以安全删除派生类对象return 0;
}

2. 多态的实现原理

(1)静态多态

原理:函数名修饰。编辑器会根据函数的签名(包括参数类型、数量和顺序)对内部的函数名称进行编码,生成一个唯一的标识符。这个编码后的名称包含了足够的信息,使得编译器能够准确地区分不同的重载版本,即使它们的外部名称相同。

编译过程:

        预编译:把头文件中的函数声明拷贝到源文件,避免编译过程中语法分析找不到函数定义。

        编译:语法分析,同时进行符号汇总

        汇编:生成函数名到函数地址的映射,方便之后通过函数名照到函数定义从而执行函数。

        链接:讲过个文件的符号表汇总合并

早绑定:编译器编译时就已经确定对象调用的函数的地址。静态多态依赖于早绑定。

(2)动态多态

原理:虚函数重写。当一个类中声明了至少一个虚函数时,编译器会为该类生成一个虚函数表。这是一个存储虚函数指针的数组,每个指针指向类中相应虚函数的实现。含有虚函数的类实例在内存中除了包含数据成员外,还会有一个指向其所属类的虚函数表的指针(通常称为vptr)。这个vptr是在对象创建时由编译器自动初始化的。在派生类中,当你定义了一个与基类中虚函数同名且签名相同的函数时,这就是虚函数的重写。派生类的虚函数表中,对应的条目会存储派生类中该函数的地址,而非基类的。

虚函数重写:基类函数上加上virtual关键字,在派生类重写虚函数。运行时会根据对象的类型调用相应的函数。如果对象的类型是基类,那么调用基类的函数,如果对象的类型是派生类诶,则调用派生类的函数

晚绑定:程序运行时才确定对象调用的函数的地址。动态多态依赖于晚绑定。C++中,晚绑定是通过virtual关键字实现的。

3. 怎么解决菱形继承

因为c++有多重继承的特性,导致一个子类可能继承多个基类。这些基类可能继承自相同的基类,从而造成了菱形继承。

菱形继承的问题主要是数据冗余并且造成二义性。

二义性:当一个派生类(我们称之为D)从两个不同的基类(比如B1B2)继承,而这两个基类又都继承自同一个基类(A),那么在D中直接访问从A继承来的成员时,编译器无法确定应该使用B1继承的版本还是B2继承的版本。这种情况下,编译器会报错,指出存在二义性。

数据冗余:如果不使用虚拟继承(virtual关键字),每个派生类(B1B2)都会包含基类A的一个完整副本。因此,当D继承自B1B2时,它将拥有两份A的成员,导致数据冗余。这不仅浪费存储空间,还可能导致逻辑上的混乱,尤其是在修改这些成员时,可能会忘记更新所有副本,从而引发一致性问题。

使用虚继承可以解决菱形继承问题。在派生类对共同基类进行虚继承时,编译器会确保只有一份共同基类的实例,而不是每个中间类都有自己的一份。

4. 关键字override、final的作用

子类继承基类的虚函数之后,可能存在这样的问题:子类不希望这个函数会自己的子类被进一步重写;子类想重写一个新函数,但是错误的重写了基类虚函数;子类本意是重写基类的虚函数但是签名不一致导致重新构建了一个虚函数;子类希望自己绝后!但是没有办法从语法上完成这件事。

override可以指定子类的一个虚函数复写基类的一个虚函数;并且保证该重写的虚函数与子类的虚函数有相同的签名。

final可以指定某个虚函数不能在派生类中覆盖,或者某个类不能被派生。加在类前面就可以阻塞类的进一步派生。

5. C++类型推导的用法

C++类型推导主要有三个方面:auto、decltype、模板类型推导

(1)auto:用于推导变量的类型,通过强制声明一个变量的初始值,编译器会通过初始值进行推导类型

(2) decltype

用于推导表达式的类型,编译器只分析表达式类型而不参与运算

 6. C++11 中function、lambda、bind之间的关系

std::function是一个抽象了函数参数和函数返回值的类模板。它把任意函数包装成了一个对象,该对象可以保存传递以及复制。也可以进行动态绑定,只需要修改该对象,实现类似多态的效果

#include <iostream>
#include <functional>// 函数对象(仿函数)
struct Adder {int operator()(int a, int b) const {return a + b;}
};// 普通函数
int subtract(int a, int b) {return a - b;
}// 成员函数
struct Calculator {int multiply(int a, int b) {return a * b;}
};int main() {// 使用 std::function 声明不同类型的可调用对象std::function<int(int, int)> func1 = Adder();  // 函数对象std::function<int(int, int)> func2 = subtract; // 普通函数Calculator calc;std::function<int(Calculator&, int, int)> func3 = &Calculator::multiply;  // 成员函数// 调用并输出结果std::cout << "Adder result: " << func1(10, 5) << std::endl;std::cout << "Subtract result: " << func2(10, 5) << std::endl;std::cout << "Multiply result: " << func3(calc, 10, 5) << std::endl;return 0;
}

lambda表达式:一种方面的创建匿名函数的语法糖

原理:编译的时候把表达式转变为一个函数对象,然后根据表达式惨呼列表重载operate ()

demo:

// 简单表达式
auto sayHello = []{ std::cout << "Hello, World!\n"; };
sayHello();// 捕获外部变量
int x = 10, y = 20;
auto incrementAndPrint = [x, &y]() {x++; // 按值捕获,不会改变外部xy++; // 按引用捕获,会改变外部ystd::cout << "x: " << x << ", y: " << y << "\n";
};
incrementAndPrint(); // 输出:x: 11, y: 21
std::cout << "After: x=" << x << ", y=" << y << "\n"; // 输出:x=10, y=21// 指定返回类型
int x = 10, y = 20;
auto incrementAndPrint = [x, &y]() {x++; // 按值捕获,不会改变外部xy++; // 按引用捕获,会改变外部ystd::cout << "x: " << x << ", y: " << y << "\n";
};
incrementAndPrint(); // 输出:x: 11, y: 21
std::cout << "After: x=" << x << ", y=" << y << "\n"; // 输出:x=10, y=21

std::bind:用来通过绑定函数以及函数参数的方式生成函数对象的模板函数,提供占位符,实现灵活的参数绑定

#include <iostream>
#include <functional>// 通用加法函数
int add(int x, int y) {return x + y;
}int main() {// 使用std::bind固定add的第一个参数为5auto addFive = std::bind(add, 5, std::placeholders::_1);// 现在addFive是一个新的可调用对象,只需要一个参数std::cout << "Adding 5 to 3 gives: " << addFive(3) << '\n'; // 输出: 8std::cout << "Adding 5 to 10 gives: " << addFive(10) << '\n'; // 输出: 15return 0;
}

总结:function 用来描述函数对象的类型;lambda 表达式用来生成函数对象(可以访问外部变量的匿名函数);bind 也是用来生成函数对象(函数和参数进行绑定生成函数对象);

这是一条吃饭博客,由挨踢零声赞助。学C/C++就找挨踢零声,加入挨踢零声,面试不挨踢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/42487.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为机试HJ37统计每个月兔子的总数

华为机试HJ37统计每个月兔子的总数 题目&#xff1a; 想法&#xff1a; 上述题目实际是一个斐波那契数列&#xff0c;利用斐波那契数列对问题进行求解 input_number int(input())def fib(n):if n < 2:return 1else:n_1 1n_2 1count 2while count < n:n_1, n_2 n_…

【AI资讯】可以媲美GPT-SoVITS的低显存开源文本转语音模型Fish Speech

Fish Speech是一款由fishaudio开发的全新文本转语音工具&#xff0c;支持中英日三种语言&#xff0c;语音处理接近人类水平&#xff0c;使用Flash-Attn算法处理大规模数据&#xff0c;提供高效、准确、稳定的TTS体验。 Fish Audio

机器学习Day12:特征选择与稀疏学习

1.子集搜索与评价 相关特征&#xff1a;对当前学习任务有用的特征 无关特征&#xff1a;对当前学习任务没用的特征 特征选择&#xff1a;从给定的特征集合中选择出相关特征子集的过程 为什么要特征选择&#xff1f; 1.任务中经常碰到维数灾难 2.去除不相关的特征能降低学习的…

Git注释规范

主打一个有用 代码的提交规范参考如下&#xff1a; init:初始化项目feat:新功能&#xff08;feature&#xff09;fix:修补bugdocs:文档&#xff08;documentation&#xff09;style:格式&#xff08;不影响代码运行的变动&#xff09;refactor:重构&#xff08;即不是新增功能…

计算机网络之令牌环

1.令牌环工作原理 令牌环&#xff08;Token Ring&#xff09;是一种局域网&#xff08;LAN&#xff09;的通信协议&#xff0c;最初由IBM在1984年开发并标准化为IEEE 802.5标准。在令牌环网络中&#xff0c;所有的计算机或工作站被连接成一个逻辑或物理的环形拓扑结构。网络中…

排序(2)

我们在排序&#xff08;1&#xff09;中说到选择排序的代码&#xff1a; void SelectSort(int* a,int n) {int begin0,endn-1;int minibegin,maxbegin;for(int ibegin1;i<end;i){if(a[i]>a[max]){maxii;}if(a[i]<a[mini]){minii;}begin;--end;}Swap(&a[beign],&a…

SKF轴承故障频率查询

1&#xff0c;第一步&#xff1a;搜索轴承型号 skf官网 2&#xff0c;第二步&#xff1a;查询故障频率。 第三步&#xff1a;

尚品汇-(十四)

&#xff08;1&#xff09;提交git 商品后台管理到此已经完成&#xff0c;我们可以把项目提交到公共的环境&#xff0c;原来使用svn&#xff0c;现在使用git 首先在本地创建ssh key&#xff1b; 命令&#xff1a;ssh-keygen -t rsa -C "your_emailyouremail.com" I…

落日余晖映晚霞

落日余晖映晚霞&#xff0c;立于海滨&#xff0c;望夕阳余晖洒于波光粼粼之上&#xff0c;金光跳跃&#xff0c;若繁星闪烁&#xff0c;耀人心目。 海风轻拂&#xff0c;心境宁静&#xff0c;凡尘俗务皆于此刹那消散&#xff0c;思绪万干&#xff0c;或忆往昔点滴&#xff0c;或…

刷爆leetcode第十期

题目一 相同的树 给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 首先我们要来判断下它们的根是否相等 根相等的话是否它们的左子树相等 是否…

在CMD中创建虚拟环境并在VSCode中使用和管理

1. 使用Conda创建虚拟环境 在CMD或Anaconda Prompt中执行以下代码以创建一个新的虚拟环境&#xff1a; conda create -n my_env python 3.8 这样会创建一个名为 my_env 的环境&#xff0c;并在Anaconda环境目录下生成一个相应的文件夹&#xff0c;包含该虚拟环境所需的所有…

GD32实战篇-双向数控BUCK-BOOST-BOOST升压理论基础

本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发 向上代码兼容GD32F450ZGT6中使用 后续项目主要在下面该专栏中发布&#xff1a; https://blog.csdn.net/qq_62316532/category_12608431.html?spm1001.2014.3001.5482 感兴趣的点个关注收藏一下吧! 电机驱动开发可以跳转…

MySQL之备份与恢复(八)

备份与恢复 还原逻辑备份 如果还原的是逻辑备份而不是物理备份&#xff0c;则与使用操作系统简单地复制文件到适当位置的方式不同&#xff0c;需要使用MySQL服务器本身来加载数据到表中。在加载导出文件之前&#xff0c;应该先花一点时间考虑文件有多大&#xff0c;需要多久加…

C++ 函数高级——函数的占位参数

C中函数的形参列表里可以有占位参数&#xff0c;用来做占位&#xff0c;调用函数时必须填补改位置 语法&#xff1a; 返回值类型 函数名&#xff08;数据类型&#xff09;{ } 在现阶段函数的占位参数存在意义不大&#xff0c;但是后面的课程中会用到该技术 示例&#xff1a;…

STM32快速复习(八)SPI通信

文章目录 前言一、SPI是什么&#xff1f;SPI的硬件电路&#xff1f;SPI发送的时序&#xff1f;二、库函数二、库函数示例代码总结 前言 SPI和IIC通信算是我在大学和面试中用的最多&#xff0c;问的最多的通信协议 IIC问到了&#xff0c;一般SPI也一定会问到。 SPI相对于IIC多了…

含并行连结的网络

一、Inception块 1、白色部分通过降低通道数来控制模型复杂度&#xff0c;蓝色做特征提取工作&#xff0c;每条路上的通道数可能不同&#xff0c;大概我们会把更重要的那部分特征分配更多的通道数 2、Inception只改变高宽&#xff0c;不改变通道数 3、在不同的情况下需要选择…

pin是什么?管脚

1.平面分割 1)启动Allegro PCB design &#xff0c;打开.brd。深色部分属于一个net&#xff0c;要做一下修改&#xff0c;将上面的pin包含进shape中&#xff0c;i进行a&#xff0c;b两步操作&#xff0c;删除以前存在的Anti Etch下的line&#xff0c;再将其进行补齐 使它保住上…

【帧中继实验-ensp】

实验要求 在R1上开启一个点对点子接口&#xff0c;用于连接 R1–R2&#xff0c;两端IP地址为12.1.1.x 。开启一个多点子接口 &#xff0c;用于连接R1–R3&#xff0c;R4&#xff0c;两段IP地址为134.1.1.x。 具体DLCI分配和映射关系如下&#xff1a; R1 102 R2 201—动态映射…

论文略读:Can Long-Context Language Models Subsume Retrieval, RAG, SQL, and More?

202406 arxiv 1 intro 传统上&#xff0c;复杂的AI任务需要多个专门系统协作完成。 这类系统通常需要独立的模块来进行信息检索、问答和数据库查询等任务大模型时代&#xff0c;尤其是上下文语言模型&#xff08;LCLM&#xff09;时代&#xff0c;上述问题可以“一体化”完成…

《python程序语言设计》2018版第5章第53题利用turtle绘制sin和cos函数 sin蓝色,cos红色和52题类似

直接上题和代码 5.53 &#xff08;Turtle&#xff1a;绘制sin和cos函数&#xff09;编写程序绘制蓝色的sin函数和红色的cos函数。 代码和结果 turtle.speed(10) turtle.penup() # sin 用蓝色 turtle.color("blue") #这道题和上道题一样&#xff0c;先把turtle放到起始…