C++类细节,反汇编,面试题02

news2024/11/25 16:26:52

文章目录

  • 2. 虚函数vs纯虚函数
  • 3. 重写vs重载vs隐藏
    • 3.1. 为什么C++可以重载?
  • 4. struct vs union
    • 4.1. 为什么要内存对齐?
  • 5. static作用
  • 6. 空类vs空结构体
    • 6.1. 八个默认函数:
    • 6.2. 为什么空类占用1字节
  • 7. const作用
    • 7.1 指针常量vs常量指针vs常量指针常量
  • 8. 接口vs抽象类
  • 9. 浅拷贝vs深拷贝
    • 9.1. 深拷贝应用场景
    • 9.2. 调用拷贝构造函数的三种情况
  • 10. 写时拷贝

2. 虚函数vs纯虚函数

  • virtual修饰的成员函数就是虚函数,它允许在子类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和子类的同名函数。引入虚函数是为了动态绑定。
  • 纯虚函数除了关键字virtual外,还要 =0, 它是在基类中声明但没有定义的虚函数,要求子类必须提供实现。引入纯虚函数是为了派生接口,即子类仅仅只是继承函数的接口。

3. 重写vs重载vs隐藏

  • 重写:发生继承关系中,子类重写父类的方法。
  • 重载:发生在同一个类中,函数名相同,但参数个数或类型不同。
  • 隐藏:子类函数屏蔽了与其同名的基类函数,有以下两种情况:
    1、参数不同,基类函数被隐藏 (而不是重载)
    2、参数相同,但基类函数没有virtual关键字,基类函数被隐藏 (而不是重写)

3.1. 为什么C++可以重载?

  • C++引入了命名空间,以及作用域,比如类作用域,命名空间作用域。
  • 函数在编译期间,链接符号的时候,会在符号后追加一些特殊标识,比如add函数,变成add@123。

4. struct vs union

  • 相同:都可以将不同类型的变量组合成一个整体。
  • 区别
    • struct 里的每个成员都有自己独立的内存空间;sizeof(struct) 是内存对齐后所有成员长度的总和。
    • union 里的所有成员共享同一内存空间;sizeof(union) 是内存对齐后最大的数据成员长度。

4.1. 为什么要内存对齐?

  • 确保代码在不同平台上的兼容性。
  • 提高内存访问的效率。
  • ps:在Visual Studio中,默认对齐值8,将它与结构体中最大的数据成员长度进行比较,取两者的较小值,设定为实际对齐值。

5. static作用

  • static修饰的成员变量就是类变量,是类的所有对象共有的。
  • static修饰的成员函数就是类方法,类方法不能访问对象变量只能访问类变量,可以由类名直接调用,也可以由对象调用。
  • static修饰的局部变量就是局部静态变量,在函数内可以访问到。
  • static修饰的全局变量就是全局静态变量,是当前文件内可以访问到。
  • ps:对象变量,是每个对象单独拥有的。
  • ps:const强调值不能被修改,而static强调内存只有一份拷贝。

6. 空类vs空结构体

  • 空类:默认private。
  • 空结构体:默认public。

6.1. 八个默认函数:

  • 构造函数 【A();】
  • 析构函数 【~A();】
  • 拷贝构造函数 【A (const A&);】
  • 重载赋值运算符 【A&operator = (const A&);】
  • 重载取址运算符 【A* operator& ();】
  • 重载取址运算符const 【const A* operator& () const;】
  • 移动构造函数(C++11) 【A(A&&);】
  • 重载移动赋值运算符(C++11)【A& operator = (const A&&);】

6.2. 为什么空类占用1字节

  • 因为如果对象完全不占用内存空间,空类就无法取得实例的地址,this指针失效,因此不能被实例化。而类的定义是由数据成员和成员函数组成的,在没有数据成员情况下,还可以有成员函数,因此仍然需要实例化。

7. const作用

  • 限定变量不可修改。
  • 限定成员函数不可修改数据成员(后置const)。
  • 成员函数的返回值类型是const,则返回值不是左值(前置const)。
  • 用const对函数的参数修饰,表面是输入参数,在函数内不可写。
  • const函数只能调用const函数,非const函数可以调用const函数。

7.1 指针常量vs常量指针vs常量指针常量

  • 指针常量,即指针本身是常量,所以指针的值(内存地址)不能改变,示例如下。
    int a = 10, b = 20;
    int* const p= &a;
    p = &b;  //错误,指针存放的内存地址不可变
    *p= 100; //正确,内存地址存放的内容可以改变
  • 常量指针,即指向常量的指针,不能通过指针修改指向的内容,示例如下。
    const int a = 10;
    int b = 20;
    const int* p = &a;
    p = &b; //正确, 指针存放的内存地址可变
    *p = 100; //错误,指针指向的内容不可变
    b = 100; //正确,可以通过原来的声明修改
  • 常量指针常量,即指向常量的指针本身也是常量,不能通过指针修改指向的值,指针的值不能改变,示例如下。
    const int a = 10;
    int b = 20;
    const int* const p = &a;
    p = &b; //错误, 指针存放的内存地址不可变
    *p = 100; //错误,指针指向的内容不可变

8. 接口vs抽象类

  • 抽象类:带有纯虚函数的类。
    抽象类作用:为了扩展和重用。
  • 接口:没有数据成员;成员函数都是公有的、都是纯虚函数,虚析构函数除外;是完全抽象的类。
    接口作用:只提供了一种规范,实现接口的类必须实现接口中的所有方法。
  • 相同:都不能实例化,但可以创建指针。
  • 代码如下。
// ConsoleApplication5.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include<iostream>
using namespace std;

//抽象类
class Shape 
{
protected: 
    //数据成员:价格和面积
    double price; 
    double area; 

public:
    //构造函数
    Shape() :price(100),area(0) {} 

    //虚析构函数
    virtual ~Shape() { printf("%s\n", "Delete shape"); } 

    //纯虚函数:获取图形描述和获取价格
    virtual void getDescription() = 0; 
    virtual void getPrice() = 0;
};

//接口
class Draw
{
public:
    //虚析构函数
    virtual ~Draw() { printf("%s\n", "Delete Draw"); }

    //纯虚函数:输出图形周长
    virtual void drawLen() = 0;  
};

//具体类
class Circle : public Shape,public Draw
{
private:
    double radius; 

public:
    Circle(double r) : radius(r) { area = 3.14 * radius * radius; price = 100 + area * 6; }
    ~Circle() { printf("%s%f\n", "Delete circle with radius ",radius); }

    void getDescription() { printf("%s%f\n", "Circle with radius ",radius);}
    void getPrice(){ printf("%s%f%s%f\n", "Circle with area ", area," price ",price); }
    void drawLen() { printf("%s%f\n", "Circle with len ", 2 * 3.14 * radius); }
};



int main() {
   
    Circle c(5.0);

    Shape* s = &c; //基类(Shape)指针指向子类(Circle)对象
    s->getDescription();
    s->getPrice();
    
    Draw* d = &c;  //基类(Draw)指针指向子类(Circle)对象
    d->drawLen();

    _CrtDumpMemoryLeaks();
    return 0;
}

  • 程序执行结果,如下图。

在这里插入图片描述

9. 浅拷贝vs深拷贝

  • 浅拷贝只是将指针拷贝,指向同一块内存。
  • 深拷贝是直接将内存拷贝一份。

9.1. 深拷贝应用场景

  • 【注意】 当类成员变量是指针,为它动态分配内存时,有以下两种bug情况:
    1、若使用默认的重载赋值运算符进行浅拷贝,即a和b指向同一内存,但b曾指向的内存不会被删除,造成内存泄漏;若一方离开了它的生存空间,使用析构函数释放资源,另一方会变成悬空指针,导致未定义行为;同时当另一方调用析构函数时,会因重复释放同一堆空间而触发中断。
    2、若使用默认的拷贝构造函数进行浅拷贝,会重复释放同一内存。
    所以,为避免这两种bug情况,需要进行深拷贝。
  • 修改一个对象不会影响到另一个对象时,进行深拷贝以确保每个对象都有自己独立的数据副本。

9.2. 调用拷贝构造函数的三种情况

  • 用一个对象去初始化另一个对象时。
  • 当函数的参数是对象时,形参是实参的副本,即拷贝构造了一个新对象。
    • vs 但当函数的参数是对象引用或对象指针时,是直接传递对象this指针,无需拷贝。
  • 当函数的返回值是对象引用时,由于临时对象离开了函数就会消失,所以要对临时对象进行拷贝,构造一个新对象。【注意】 当临时对象出了函数作用域后,存放它数据的那块内存随时会被占用,写入新数据,所以在拷贝构造过程中 【存在安全隐患】,即它可能拷贝别的内容,代码和反汇编如下。
    • vs 但当函数的返回值是对象指针时,由于指针指向临时对象,所以临时对象还没消失,并且也无需进行拷贝。
    • vs 【注意】 但当函数的返回值是对象时,不一定会调用拷贝构造函数,因为C++编译器通常会进行返回值优化,即它直接传递保存返回值的对象this指针,然后在函数内直接构造,由于这个对象是在函数外定义的,所以不会受函数作用域的影响。
#include <iostream>
using namespace std;

class A {
private:
    int data;
public:
    A(int i) { data = i; } 	

    A(const A& a)
    {
        data = a.data;
        cout << "拷贝构造函数执行完毕" << endl;
    }
   
};

A& getA() {
    A a(3);
    return a;
}

int main() {
    
    A d1 = getA();      		    			
    return 0;
}

eax保存返回的临时对象地址,如下图。
在这里插入图片描述
由于临时对象的内存空间被占用了,写入了新数据,所以新对象拷贝了错误的内容,如下图。
在这里插入图片描述

10. 写时拷贝

  • 在使用系统重要的dll或者系统一些函数的时候,系统为了节省空间和提高性能,会直接映射一份共享地址,但当我们对其进行修改时,会触发写时拷贝,会拷贝一份给我们进程内使用,防止我们去修改共享的地址,影响整个系统。

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

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

相关文章

k8s v1.20二进制部署

目录 一、环境准备 二、操作系统初始化配置 2.1.关闭防火墙 ​编辑 2.2.关闭selinux 2.3.关闭swap 2.4.根据规划设置主机名 2.5在master添加hosts 2.6.调整内核参数 2.7.时间同步 三、部署 docker引擎 3.1.所有 node 节点部署docker引擎 四、部署 etcd 集群 4.1.…

【云计算小知识】云管理的作用是什么?

云计算已经成为推动企业数字化转型&#xff0c;提升运营效率的重要力量。而在这个过程中&#xff0c;云管理作为确保云计算环境稳定、高效运行的关键环节&#xff0c;其作用愈发凸显。今天我们小编就给大家详细介绍一下云管理的作用是什么&#xff1f; 云管理的作用是什么&…

找不到mfc140.dll是什么意思?四种高效率方法修复mfc140.dll文件

软件运行过程中的错误和问题偶尔会发生&#xff0c;这可能导致不便和工作效率的降低。其中一个常见的问题是“找不到 mfc140.dll”错误消息&#xff0c;这会阻止某些基于 Microsoft Visual Studio 2015 编写的应用程序运行。mfc140.dll 是一个重要的系统文件&#xff0c;今天我…

Whistle Web Debugging Proxy介绍及使用

大家好&#xff0c;今天继续给大家分享一款抓包工具&#xff0c;这款抓包工具是网页的形式&#xff0c;方便多人访问同时维护。Whistle Web Debugging Proxy是一个用于HTTP、HTTPS、WebSocket等网络协议的跨平台调试工具。它可以帮助开发者对网络请求进行捕捉、分析、修改和重定…

Spring Boot项目怎么集成Gitee登录

一、背景 现在的越来越多的项目&#xff0c;需要集成第三方系统进行登录。今天我们以Spring Boot项目集成Gitee为例&#xff0c;演示一下怎么使用Oauth2协议&#xff0c;集成第三方系统登录。 不了解oauth2的&#xff0c;可以看我之前的文章。Ouath2是怎么实现在第三方应用认…

Java入门基础学习笔记21——Scanner

在程序中接收用户通过键盘输入的数据&#xff1a; 需求&#xff1a; 请在程序中&#xff0c;提示用户通过键盘输入自己的姓名、年龄、并能在程序中收到这些信息&#xff0c;怎么解决&#xff1f; Java已经写好了实现程序&#xff0c;我们调用即可。 API&#xff1a;Applicat…

Linux---vim编辑器(续写)

5. vim正常模式命令集 插入模式 按「i」切换进入插入模式「insert mode」&#xff0c; 按“i”进入插入模式后是从光标当前位置开始输入文件&#xff1b; 按「a」进入插入模式后&#xff0c;是从目前光标所在位置的下一个位置开始输入文字&#xff1b; 按「o」进入插入模式…

APP未上架应用市场,微信商户如何快速开通APP支付

在移动互联网时代&#xff0c;APP作为企业服务用户的重要窗口&#xff0c;其支付功能的完善性直接关系到用户体验和企业的营收。然而&#xff0c;对于许多未上架应用市场的APP来说&#xff0c;如何快速开通微信APP支付功能成为了一个亟待解决的问题。本文将为您详细介绍在APP未…

MetaRTC-push推流客户端代码分析

本demo渲染使用opengl&#xff0c;音频采集使用alsa&#xff0c;视频采集使用v4l2/dev/video。 在设计多个平台时&#xff0c;MetaRTC的源码和google的c webrtc源码都使用了工厂模式的方法&#xff0c;比如以下不同平台的视频采集为例子。YangVideoCaptureLinux是实现linux平台…

将macOS系统安装到外置硬盘上教程

常常因为Mac昂贵的价格&#xff0c;我们会选择低容量的硬盘版本&#xff0c;造成很多大型游戏都安装不了的尴尬境地。今天&#xff0c;我们要探讨一个非常实用的话题&#xff1a;如何给你的Mac电脑扩容&#xff0c;通过将macOS系统安装到外置硬盘上。这对于希望提升存储空间但又…

基于GD32的简易数字示波器(5)- 软件_控制LED

这期记录的是项目实战&#xff0c;做一个简易的数字示波器。 教程来源于嘉立创&#xff0c;帖子主要做学习记录&#xff0c;方便以后查看。 本期主要介绍GPIO口的输入输出模式&#xff0c;使用其中的输出模式驱动LED。详细教程可观看下方链接。 2.2 LED控制实验 语雀 1、LE…

表征和基于结构的蛋白质工程:黄芪特异性皂苷乙酰转移酶-文献精读14

Characterization and structure-based protein engineering of a regiospecific saponin acetyltransferase from Astragalus membranaceus 表征和基于结构的蛋白质工程&#xff1a;黄芪特异性皂苷乙酰转移酶&#xff0c;一篇乙酰基转移酶文章精读分享~ 摘要 乙酰化有助于许…

一文入门DNS

概述 DNS是一个缩写&#xff0c;可以代表Domain Name System&#xff0c;域名系统&#xff0c;是互联网的一项基础服务。也可以代表Domain Name Server&#xff0c;域名服务器&#xff0c;是进行域名和与之相对应的IP地址相互转换的服务器。DNS协议则是用来将域名转换为IP地址…

pgbackrest 备份工具使用 postgresql

为啥我会使用pgbackrest进行备份&#xff1f;因为postgresql没有自带的差异备份工具。。。而我们在生产环境上&#xff0c;一般都需要用到差异备份或者增量备份。我们的备份策略基本是&#xff0c;1天1次完整备份&#xff0c;1个小时1次差异备份。如果只需要完整备份&#xff0…

基于SSM的理发店会员管理系统的设计和实现(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的理发店会员管理系统的设计和实现&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0…

☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼

准备好了么 目录&#xff1a; 一用两个队列实现栈&#xff1a; 1思路&#xff1a; 2画图理解&#xff1a; 3代码解答&#xff1a; 二用两个栈实现队列&#xff1a; 1思路&#xff1a; 2画图理解&#xff1a; 3代码解答&#xff1a; 三设计循环队列&#xff1a; 1思路…

使用Docker+Jar方式部署微服务工程(前后端分离)看着一篇就够了

本篇教程的使用到的技术有springboot、springcloud、Nacos、Docker、Nginx部署前后端分离访问的微服务。 部署一下Nacos 首先我们需要在服务器中&#xff08;或者本地部署启动一下Nacos&#xff09;&#xff0c;这里我采用服务器的方式进行部署&#xff0c;这里有一点不一样的…

vue3 第二十八节 (vue3 事件循环之JS事件循环)

1、什么是事件循环 事件循环就是消息队列&#xff0c;是浏览器渲染主线程的工作方式&#xff1b; 过去将消息队列&#xff0c;简单的分为宏任务 和微任务 两种队列&#xff0c;而对于现在复杂多变的浏览器环境&#xff0c;显然这种处理方式已经不能满足使用&#xff0c;取而代…

如何开通微软必应bing国内竞价广告账户?

微软必应Bing作为全球第二大搜索引擎&#xff0c;凭借其特有的用户群和市场定位&#xff0c;为中国广告主开辟了一片潜力无限的蓝海市场。云衔科技通过专业实力&#xff0c;为广告主提供全方位支持&#xff0c;从开户到代运营&#xff0c;助力企业扬帆起航。 一、微软必应bing…

图的概念、性质和存储与简单遍历

前置知识&#xff1a;树的基本概念及性质 为了保证学习效果&#xff0c;请保证已经掌握前置知识之后&#xff0c;再来学习本章节&#xff01;如果在阅读中遇到困难&#xff0c;也可以回到前面章节查阅。 学习目标 掌握图的基本概念掌握图的一些性质 图的概念 基本概念 图 (…