当前位置: 首页 > news >正文

C++面试题和笔试题(五)

一、

#include <iostream>  
using namespace std;  class Base {  
public:  Base(int j) : i(j) {}  virtual ~Base() {}  void func1() {  i *= 10;  func2();  }  int getvalue() {  return i;  }  
protected:  virtual void func2() {  i++;  }  
protected:  int i;  
};  class Child : public Base {  
public:  Child(int j) : Base(j) {}  void func1() {  i *= 100;  func2();  }  
protected:  void func2() {  i += 2;  }  
};  int main() {  Base* pb = new Child(1);  pb->func1();  cout << pb->getvalue() << endl;  delete pb;  return 0;  
}

输出的结果是(102)

官方解释:

  1. 基类Base:定义了一个整数成员i和两个虚函数func1func2func1函数首先将i乘以10,然后调用func2func2在基类中的实现是将i加1。

  2. 派生类Child:从Base类公开继承。它重写了func1func2函数。在Child中,func1首先将i乘以100,然后调用func2func2在派生类中的实现是将i加2。

  3. main函数:创建了一个指向Child对象的Base指针pb。通过pb调用func1函数。由于多态性,将调用Child类中的func1。最后,输出i的值并删除动态分配的对象。

程序的输出将取决于func1func2的调用顺序以及它们在基类和派生类中的实现。在这个例子中,由于Child类重写了func1func2,所以最终i的值将会是1 * 100 + 2 = 102Child类的func1乘以100,然后Child类的func2加2)。输出将是102

自己的理解:

假设现在我们有两个这样的魔法盒子,一个是爸爸的,一个是孩子的。爸爸的盒子只有“变大10倍并加1”这个按钮,而孩子的盒子既有“变大10倍并加1”按钮,又有“变大100倍并加2”按钮。

但是,孩子很调皮,他把他的盒子给了爸爸,并且让爸爸以为这就是他的盒子。当爸爸按下“变大10倍并加1”这个按钮时,其实他按的是孩子盒子的按钮,所以盒子的东西会按照孩子的规则来变大。

假设一开始盒子里有1个苹果,当爸爸按下按钮后,这个苹果会先变成100个(因为是按照孩子的盒子的“变大100倍”规则),然后再加2个,最后盒子里就有102个苹果了。

最后,爸爸会告诉我们盒子里有多少个苹果,我们就知道了。

在这个例子中,爸爸的盒子就像是基类Base,孩子的盒子就像是派生类Child。爸爸按下的按钮就像是基类的函数func1,而孩子盒子的特殊功能就像是派生类重写的函数。因为爸爸实际上拿的是孩子的盒子,所以按下按钮后,会按照孩子的规则来变化

考点

  1. 多态性:通过基类指针调用派生类对象的虚函数时,实际调用的是派生类中定义的版本。这里 pb->func1(); 和 pb->func2(); 展示了多态性的使用。

  2. 虚函数func2 被声明为 protected 和 virtual,这意味着它可以在派生类中被重写,同时保证多态性的行为。

  3. 构造函数和析构函数:构造函数用于初始化对象,析构函数用于清理对象。这里 Base 和 Child 类的构造函数展示了如何初始化基类成员变量,而析构函数则展示了如何安全地销毁对象。

  4. 继承Child 类公开继承自 Base 类,这意味着 Child 对象可以使用 Base 类的公有和保护成员。

  5. 访问控制Base 类中的 func2 和 i 被声明为 protected,这意味着它们可以在派生类中被访问,但不能从 Base 类的对象直接访问。

  6. 内存管理:使用 new 和 delete 进行动态内存分配和释放是 C++ 中的一个重要概念,这里展示了如何正确地使用它们。

  7. 错误处理:虽然代码中没有显式展示错误处理,但在实际编程中,处理动态内存分配失败(虽然在现代系统上很少见)或其他异常情况也是重要的考点。

 二、改错题

1)

void GetMemory(char*p)
{
p=(char*)malloc(100);
}
void Test(void)
{
char *str=NULL;
GetMemory(str);
strcpy(str,"hello world");
printf(str);
}

问题一:GetMemory 函数中的指针修改不反映到 Test 函数中。
在 GetMemory 函数中,p 是一个指向 char 的指针的本地副本。当你将 p 指向 malloc 分配的内存时,Test 函数中的 str 并没有改变,因为它传递的是 str 的一个副本,而不是 str 本身的地址。因此,Test 函数中的 str 仍然是 NULL

问题二:内存泄漏。
由于 GetMemory 函数中的 malloc 分配的内存没有被释放,这会导致内存泄漏。

问题三:strcpy 可能导致未定义行为。
由于 str 是 NULL,尝试使用 strcpy 将字符串复制到它指向的位置会导致未定义行为,通常是程序崩溃。

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  void GetMemory(char **p) {  *p = (char*)malloc(100);  if (*p == NULL) {  // 错误处理,分配内存失败  exit(EXIT_FAILURE);  }  
}  void Test(void) {  char *str = NULL;  GetMemory(&str); // 传递str的地址  if (str != NULL) {  strcpy(str, "hello world");  printf("%s\n", str);  free(str); // 释放分配的内存  }  
}  int main() {  Test();  return 0;  
}
  1. GetMemory 函数现在接受一个指向 char 指针的指针(即 char **),这样它就可以修改 Test 函数中的 str
  2. 使用 malloc 分配内存后,我们检查是否成功分配了内存。
  3. 在 Test 函数中,我们检查 str 是否为 NULL,然后才尝试使用 strcpy
  4. 使用完分配的内存后,我们在 Test 函数中释放它,以避免内存泄漏。
  5. malloc 分配的内存应该用 free 来释放,而且应该在所有使用完这块内存的地方都这么做 

 自己的理解:

想象你有一个存钱罐,你想要放更多的钱进去,但是你还没有足够的硬币。于是,你决定去银行取一些钱。

GetMemory 函数就像是你去银行取钱的过程。你告诉银行你想要100个硬币(这就像是分配100个字节的内存)。银行给你一个装满硬币的袋子(这就像是malloc返回的内存地址)。

Test 函数就像是你回到家,想要把取回来的钱放进存钱罐里。但是,如果你忘记从银行带钱回来(也就是说,str 仍然是NULL),你尝试往存钱罐里放钱时,就会出问题,因为没有钱可以放(这会导致程序崩溃)。

为了避免这个问题,你在GetMemory函数里不是直接告诉银行你要取钱,而是告诉银行你存钱罐的地址(这就像是传递str的地址,即&str)。这样,银行就能直接把装满硬币的袋子放到你的存钱罐里。

当你把钱放进存钱罐后,记得以后不用了要把钱放回银行,不然你的家就会堆满钱,没地方放了(这就像是内存泄漏)。所以,在Test函数最后,我们使用free(str)来释放我们之前分配的内存。

这样,你就学会了如何正确地取钱(分配内存)和存钱(释放内存),而不会让家里变得乱七八糟。

2)

#include<iostream>
using namespace std;
class A
{
public:
A()
{
cout<<"new A"<<endl;
m=(char*)malloc(10);
}
~A()
{
cout<<"del A"<<endl;
}
protected:
char *m;
}
class B:public A
{
public:
B()
{
cout<<"new B"<<endl;
m=(char*)malloc(100);
}
~B()
{
cout<<"del B"<<endl;
}
protected:
char*m;
};int main()
{A*c=new B;
delete c;
}

错误和需要注意的地方:

  1. class B 中重定义了 m 成员变量。在继承关系中,如果基类 A 和派生类 B 中都有名为 m 的成员变量,那么它们将被视为两个不同的变量。这可能会导致混淆和错误。

  2. 在 main 函数中,你使用 new B 创建了一个 B 类的对象,但是将其赋值给了一个 A 类型的指针 c。虽然这是合法的(因为 B 是从 A 公有继承的),但需要注意,当你通过 A 类型的指针访问 m 成员时,你会访问到基类 A 中的 m,而不是派生类 B 中的 m

  3. 在 A 和 B 的构造函数中,你使用 malloc 为 m 分配了内存,但在析构函数中并没有使用 free 来释放这些内存。在C++中,更推荐使用 new 和 delete 来管理动态内存,因为 new 会自动调用对象的构造函数,而 delete 会自动调用析构函数。

#include<iostream>  
using namespace std;  class A {  
public:  A() {  cout << "new A" << endl;  m = new char[10]; // 使用 new 分配内存  }  virtual ~A() { // 声明为虚析构函数,确保派生类的析构函数也会被调用  cout << "del A" << endl;  delete[] m; // 使用 delete[] 释放内存  }  
protected:  char *m;  
};  class B : public A {  
public:  B() {  cout << "new B" << endl;  // 注意:这里不应该再次分配 m,因为 m 已经在 A 的构造函数中被分配了。  // 如果你确实需要在 B 中分配新的内存,你应该使用一个不同的变量名。  }  ~B() {  cout << "del B" << endl;  // 在这里,我们不需要释放 m,因为 A 的析构函数会负责释放它。  // 如果 B 有自己的内存需要释放,应该在这里做。  }  
};  int main() {  A* c = new B; // 创建 B 的对象,但用 A 的指针指向它  delete c; // 使用 delete 释放 c 指向的对象,这会先调用 B 的析构函数,然后调用 A 的析构函数  return 0;  
}

 在这个修改后的版本中,我将 A 的析构函数声明为虚函数(virtual ~A())。这是为了确保当通过基类指针删除派生类对象时,派生类的析构函数也会被调用。此外,我还使用了 new 和 delete[] 来分配和释放内存,这是C++中更推荐的做法。

3)

#include<iostrem>
using namespace std;class Test
{
public:long a;long b;virtual void fun(){}Test(long temp1=0,long temp2=0)
{a=temp1;b=temp2;
}long getA(){return a;}
long getB(){return b;}
};int maint()
{Test obj(5,10);
long * pint =(long*)&obj;
*(pint)=100;
*(pint+1)=200;
cout<<"a="<<obj.getA()<<endl;
cout<<"b="<<obj.getB()<<endl;
return 0;
}

程序在64位机器上打印输出结果是(a=100,b=200)

官方解释:

    在 main 函数中,你创建了一个 Test 类的对象 obj,并初始化了 a 为5,b 为10。然后,你创建了一个指向 long 的指针 pint,并将其设置为指向 obj 的地址。接下来,你通过 pint 修改了 obj 的内存内容。

long * pint =(long*)&obj;  
*(pint)=100;  
*(pint+1)=200;

这里,*(pint)=100; 将 obj 的起始地址(即 a 的值)设置为100。*(pint+1)=200; 将 obj 起始地址后8字节的位置(即 b 的值)设置为200。

因此,obj 的成员变量 a 和 b 现在分别被设置为100和200。

输出将是:a=100 b=200。

自己的理解:

当然可以,让我们用小学生能懂的方式和生活中的例子来解释这段代码。

首先,想象一下你有一个魔法盒子,这个盒子里面可以放两个魔法球,每个魔法球都有一个数字。这个魔法盒子就是我们代码中的Test类,而两个魔法球就是ab这两个变量。

现在,我们有一个特别的咒语,可以让这个魔法盒子里的魔法球变出数字来。这个咒语就是Test类的构造函数,它可以在我们创建魔法盒子的时候,给两个魔法球分别赋予数字。

Test(long temp1=0,long temp2=0)  
{  a=temp1;  b=temp2;  
}

比如说,我们念这个咒语:“魔法盒子,给我一个5和一个10!”然后,魔法盒子里的两个魔法球就分别变成了5和10。

main函数中,你创建了一个这样的魔法盒子,并给它念了咒语,让里面的两个魔法球变成了5和10。

接下来,你有一个魔法棒,这个魔法棒可以让你直接看到魔法盒子里面的东西。但是,你这次没有用魔法棒去看,而是直接用手去摸魔法盒子,并试图改变魔法球里的数字。

long * pint =(long*)&obj;  
*(pint)=100;  
*(pint+1)=200;

你用手伸进了魔法盒子,摸到了第一个魔法球,然后把它变成了100。接着,你又摸到了第二个魔法球,把它变成了200。

最后,你用魔法棒去看魔法盒子里的魔法球,发现它们已经变成了100和200,而不是原来的5和10了。

cout<<"a="<<obj.getA()<<endl;  
cout<<"b="<<obj.getB()<<endl;

所以,这个程序在64位机器上打印的输出结果是:a=100 b=200;

相关文章:

C++面试题和笔试题(五)

一、 #include <iostream> using namespace std; class Base { public: Base(int j) : i(j) {} virtual ~Base() {} void func1() { i * 10; func2(); } int getvalue() { return i; } protected: virtual void func2() { i; } protected: int i;…...

Mysql:行锁,间隙锁,next-key锁?

注&#xff1a;以下讨论基于InnoDB引擎。 文章目录 问题引入猜想1&#xff1a;只加了一行写锁&#xff0c;锁住要修改的这一行。语义问题数据一致性问题 猜想2&#xff1a;要修改的这一行加写锁&#xff0c;扫描过程中遇到其它行加读锁猜想3&#xff1a;要修改的这一行加写锁&…...

Grass推出Layer 2 Data Rollup

Grass推出Layer 2 Data Rollup Grass邀请链接最新资讯 Grass邀请链接 欢迎使用我的邀请码进行注册: 邀请链接 如果你还不知道注册流程&#xff1a;详见Grass: 出售闲置带宽实现被动收入 最新资讯 简讯&#xff1a;2024年3月13日&#xff0c;Grass宣布正在建立基于Solana的La…...

[Java、Android面试]_04_进程、线程、协程

本人今年参加了很多面试&#xff0c;也有幸拿到了一些大厂的offer&#xff0c;整理了众多面试资料&#xff0c;后续还会分享众多面试资料。 整理成了面试系列&#xff0c;由于时间有限&#xff0c;每天整理一点&#xff0c;后续会陆续分享出来&#xff0c;感兴趣的朋友可收藏 文…...

MyLisp项目日志:解析用户输入与波兰表达式

文章目录 编程语言模拟自然语言定义名词和形容词定义短语定义句子 简化模拟过程正则表达式 波兰表达式及其解析波兰表达式语法描述波兰表达式语法解析解析用户输入 v0.0.2 编程语言 编程语言是类似于自然语言的&#xff0c;虽然我们是自然而然就学会了自己的母语&#xff0c;但…...

torch.backends.cudnn.benchmark 作用

相关参数 torch.backends.cudnn.enabled torch.backends.cudnn.benchmark torch.backends.cudnn.deterministictorch.backends.cudnn.benchmark True&#xff1a;将会让程序在开始时花费一点额外时间&#xff0c;为整个网络的每个卷积层搜索最适合它的卷积实现算法&#xff0c…...

vue的$nextTick应用场景

文章目录 $nextTick有什么作用&#xff1f;一、NextTick是什么二、为什么要有nextTick&#xff1f; $nextTick有什么作用&#xff1f; 一、NextTick是什么 官方对其的定义 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法&#xff0c;获取更新后的…...

springboot RestTemplate 发送xml、接收xml、pojo中的属性转为属性

背景 调用第三方接口时&#xff0c;它们的系统比较老&#xff0c;只支持接收xml而不支持json&#xff0c;默认的springboot RestTemplate不支持发送xml&#xff0c;添加依赖就可以解决这个问题。 添加jackson-dataformat-xml依赖 FasterXML/jackson-dataformat-xml是一个xml…...

Lua-Lua与C++的交互2

Lua与C的交互是指在C程序中使用Lua本语言&#xff0c;或者在Lua脚本中调用C代码的过程。这种交互可以实现C与Lua之间的数据传递和函数调用。 在C中与Lua交互的主要步骤如下&#xff1a; 引入Lua库&#xff1a;首先需要在C程序中引入Lua的头文件和库文件&#xff0c;以便能够使…...

学python新手如何安装pycharm;python小白如何安装pycharm

首先找到官网&#xff1a; Download PyCharm: The Python IDE for data science and web development by JetBrains 打开后选择下载&#xff0c;下图标红部分 点击exe程序&#xff0c;点击下一步&#xff01; 选择安装路径&#xff0c;下一步 弹出界面全选 选择默认 然后直接…...

Oracle Primavera P6 数据库升级

前言 为了模拟各种P6测试&#xff0c;我常常会安装各种不同版本的p6系统&#xff0c;无论是P6服务&#xff0c;亦或是P6客户端工具Professional&#xff0c;在今天操作p6使用时&#xff0c;无意识到安装在本地的P6 数据库&#xff08;21.12&#xff09;出现了与Professional软…...

共享库的创建gcc选项“-shared -fPIC -WI”

共享库的创建非常简单&#xff0c;最关键的是gcc的几个参数&#xff1a; “-shared”&#xff1a; 表示输出结果是共享库类型。编译选项告诉编译器生成一个共享库&#xff08;也称为动态链接库或 DLL&#xff09;。共享库是一种包含可重用代码和数据的二进制文件&#xff0c;…...

微服务:Bot代码执行

每次要多传一个bot_id 判网关的时候判127.0.0.1所以最好改localhost 创建SpringCloud的子项目 BotRunningSystem 在BotRunningSystem项目中添加依赖&#xff1a; joor-java-8 可动态编译Java代码 2. 修改前端&#xff0c;传入对Bot的选择操作 package com.kob.botrunningsy…...

Python 导入Excel三维坐标数据 生成三维曲面地形图(面) 3、线条平滑曲面但有条纹

环境和包: 环境 python:python-3.12.0-amd64包: matplotlib 3.8.2 pandas 2.1.4 openpyxl 3.1.2 scipy 1.12.0 代码: import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from scipy.interpolate import griddata imp…...

Vue.js+SpringBoot开发数字化社区网格管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、开发背景四、系统展示五、核心源码5.1 查询企事业单位5.2 查询流动人口5.3 查询精准扶贫5.4 查询案件5.5 查询人口 六、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的数字化社区网格管理系统&#xf…...

java SSM农产品订购网站系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM农产品订购网站系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采…...

vsto快速在excel中查找某个字符串

是的&#xff0c;使用foreach循环遍历 Excel.Range 可能会较慢&#xff0c;特别是在大型数据集上。为了提高效率&#xff0c;你可以考虑使用 Value 属性一次性获取整个范围的值&#xff0c;然后在内存中搜索文本。这样可以减少与 Excel 之间的交互次数&#xff0c;提高性能。 …...

Unity类银河恶魔城学习记录10-1 10-2 P89,90 Character stats - Stat script源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Stat.cs using System.Collections; using System.Collections.Generic; us…...

西门子TIA中配置Anybus PROFINET IO Slave 模块

1、所需产品 Siemens S7 PLC CPU 315-2 PN/DP 6ES7 315-2EH-0AB0 Siemens PLC 编程电缆 n.a. n.a. PC ,并安装Siemens PLC编程软件 TIA Portal V11 X-gateway Slave 接口的GSDML文件 根据网关的软件版本而定 Anybus Communicator GSD文件 GSDML-V1.0-HMS-ABCPRT-20050317.xl…...

在 Rust 中使用 Serde 处理json

在 Rust 中使用 Serde 处理json 在本文中&#xff0c;我们将讨论 Serde、如何在 Rust 应用程序中使用它以及一些更高级的提示和技巧。 什么是serde&#xff1f; Rust中的serde crate用于高效地序列化和反序列化多种格式的数据。它通过提供两个可以使用的traits来实现这一点&a…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...

数据结构:递归的种类(Types of Recursion)

目录 尾递归&#xff08;Tail Recursion&#xff09; 什么是 Loop&#xff08;循环&#xff09;&#xff1f; 复杂度分析 头递归&#xff08;Head Recursion&#xff09; 树形递归&#xff08;Tree Recursion&#xff09; 线性递归&#xff08;Linear Recursion&#xff09;…...

【深度学习新浪潮】什么是credit assignment problem?

Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...