Item 05:了解C++默默编写并调用哪些函数

TypeScript调用Unreal C++实战:Puerts集成与游戏逻辑脚本化开发 在现代游戏开发中,脚本语言与原生代码的交互是提升开发效率、实现热更新的关键技术。其核心原理是通过绑定层建立脚本引擎与游戏引擎之间的通信桥梁,允许脚本直接调用引擎底层接口。这项技术的价值在于,它结合了脚本语言的快速迭代、动态类型优势与原生代码的高性能执行能力,广泛应用于游戏逻辑、UI系统、配置驱动等需要频繁修改和调试的场景。通过Puerts这样的桥接工具,开发者可以在Unreal Engine中利用TypeScript的强类型和模块化特性,实现游戏逻辑的脚本化开发,显著提升迭代速度。本文基于实战经验,详细介绍 阅读详情

Item 05: Know waht functions C++ silently writes and calls.


空类并不一定是空的

什么时候空类不再是个空类呢?答案是:当C++处理过之后。

如果你自己没声明,编译器就会为它声明(编译器版本的)一个拷贝构造函数、一个赋值操作符和一个析构函数。此外如果你没声明任何构造函数,编译器也会为你声明一个默认构造函数。所有这些函数都是public且inline的。

例如,如果你写下:

class Empty{};

这就好像写出下面这样的代码:

class Empty {
public:
    Empty() { ... }                                  // default constructor
    Empty(const Empty& rhs) { ... }                  // copy constructor
    ~Empty() { ... }                               // destructor — 是否该是
                                                     // virtual稍后说明。
    Empty& operator=(const Empty& rhs) { ... }    // copy assignment operator
};

唯有当这些函数被需要(被调用),它们才会被编译器创建出来。程序中需要它们是很平常的事。下面的代码造成上述每一个函数被编译器产生出来:

Empty e1;           // default constructor;
                      // destructor
Empty e2(e1);       // copy constructor
e2 = e1;             // copy assignment operator

编译器为你写出这些函数,但这些函数做了声明呢?默认构造函数和析构函数主要是给编译器一个地方用来放置“藏身幕后”的代码,像调用base classes和non-static成员变量的构造函数和析构函数。

注意,编译器产生出的析构函数是个non-virtual,除非这个class的base class自身声明有vitual析构函数。(这种情况下这个函数的虚属性主要来自base class)。

至于拷贝构造函数和赋值操作符,编译器创建的版本知识单纯地将来源对象的每一个non-static成员变量拷贝到目标对象。

拷贝构造函数

考虑一个NameObject template,它允许你将一个个名称和类型为T的对象产生关联:

template<typename T>
class NamedObject {
public:
    NamedObject(const char *name, const T& value);
    NamedObject(const std::string& name, const T& value);
    ...
private:
    std::string nameValue;
    T objectValue;
};

由于其中声明了构造函数,编译器于是不再为它创建default构造函数。NamedObject既没有声明拷贝构造函数,也没有声明赋值操作符,所以编译器会为它创建那些函数(如果它们被调用的话)。

NamedObject<int> no1("Smallest Prime Number", 2);
NamedObject<int> no2(no1);                          // calls copy constructor

编译器生成的拷贝构造函数必须以no1.nameValue和no1.objectValue为初值设定no2.nameValue和no2.objectValue。两者之中,nameVlaue的类型是string,而标准的string有个拷贝构造函数,所以no2.nameValue的初始化式是调用string的拷贝构造函数并以no1.nameValue为实参。另一个成员NamedObject::objectValue的类型是int,那是个内置类型,所以no2.objectValue会以“拷贝no1.objectValue内的每一个bits”来完成初始化。

拷贝赋值操作符

编译器为NamedObject所产生的赋值操作符,其行为基本上与拷贝构造函数一样,但一般而言只有当产生出的代码合法且有适当机会证明它有意义,其表现才会和我们预期的一样。万一有条件不符合,编译器会拒绝为class生出operator=。

举个例子,假设NamedObject定义如下,其中nameValue是个引用,objectValue是个const T:

template<typename T>
class NamedObject {
public:
    NamedObject(std::string& name, const T& value);
    ... 
private:
    std::string& nameValue;      // this is now a reference
    const T objectValue;        // this is now const
};

现在考虑下面会发生什么事:

std::string newDog("A");
std::string oldDog("B");

NamedObject<int> p(newDog, 2); 

NamedObject<int> s(oldDog, 36); 

p = s;      //what should happen to the data members in p?

赋值之前,不论p.nameValue和s.nameVlaue都指向string对象(当然不是同一个)。赋值动作该如何影响p.nameValue呢?赋值之后,p.nameValue应该是指向s.nameValue所指的那个string吗?也就是说reference自身可被改动吗?

面对这个难题,C++的响应是拒绝编译那一行赋值动作。因为C++并不允许“让reference改指向不同对象”。同样道理更改变const值也是非法的。如果某个base class将拷贝赋值操作符声明为private,编译器也拒绝为其derived class产生出一个拷贝赋值操作符。因为编译器为derived class生成的拷贝赋值操作符想象中可以处理base class成分,这是做不到的。

来一个具体一点的例子:

class Person{
public:
    Person(string& str,int x): name(str),value(x){ }

    string & name;
    const int value;
};


int main()
{
    string s1 = "A", s2 = "B";
    Person p1(s1,1),p2(s2,2);
    Person p3(p2);          //拷贝构造函数可以正常调用,和预期结果一样。

    cout << p1.name << " " << p1.value << endl;     //A 1
    cout << p2.name << " " << p2.value << endl;     //B 2
    cout << p3.name << " " << p3.value << endl;     //B 2

    p1 = p2;    //编译错误
                //error: non-static reference member 'std::string& Person::name', can't use default assignment operator
                //error: non-static const member 'const int Person::value', can't use default assignment operator

    return 0;
}

Note:

  • 编译器可以为class创建默认构造函数、拷贝构造函数、拷贝赋值操作符,以及析构函数。
  • 只有这些函数被调用的时候,它们才会被编译器创建出来。
  • 生成的析构函数是否为vitual,根据base class而定。
  • 如果你显式的任意定义了一个构造函数,编译器就不会为你生成一个默认构造函数了。
  • 打算在一个“内含reference成员”的 class 内支持 赋值操作,必须自己定义copy assignment操作符。
  • 面对“内含const成员”的classes,编译器的反应也一样,因为更改const成员是不合法的。
  • 如果某个 base classes 将copy assignment操作符声明为 private,编译器将拒绝为其 derived classes 生成 copy assignment 操作符。

Effective C++

2026年AI视频生成大模型全景指南:国内外主流工具深度对比与选型建议 AI视频生成技术在2025年至2026年间取得了突破性进展,从"能用"进化到"好用",商业化应用加速落地。中美双轨竞争格局基本成型,国内模型在技术追赶和本土化体验方面展现出强劲竞争力。对于用户而言,选择合适的AI视频生成工具需要综合考虑技术性能、使用门槛、成本预算和具体需求。零基础新手推荐海艺AI、通义万相等低门槛工具;进阶创作者可根据需求选择可灵AI、即梦AI、海艺AI等;专业开发者和企业用户可考虑智谱清影的开源能力或可灵AI的商业化服务。 阅读详情

相关推荐

基于 Datawhale 开源量化投资学习指南(10):基于 LightGBM 的量化选股

通过本篇文章,我们深入探索了如何运用 LightGBM 机器学习模型实现量化选股。首先,我们通过获取股票的历史数据,进行特征工程和标签制作,将选股问题转化为一个分类问题。接着,我们使用 LightGBM 训练模型,并在验证集和测试集中评估了模型的表现。该选股策略的核心在于结合机器学习算法,从历史数据中寻找能够捕捉股票短期涨跌的关键特征,从而为投资者提供辅助决策支持。虽然本文的模型取得了一定的效果,但这只是量化投资领域的一小部分。

不想宅的冷同学 1347

effective C++ 读后感(五) 了解C++默默编写并调用哪些函数

五、了解C++默默编写并调用哪些函数

warrenfws的专栏 593

别再只接个放大器了!压电传感器测量电路(电压/电荷放大器)的5个实战配置要点

本文深入解析压电传感器测量电路中的5个关键实战配置要点,包括电缆长度选择、输入阻抗匹配、过载保护设计、低频噪声抑制及放大器选型策略。特别针对电压放大器和电荷放大器的应用场景差异提供工程实践建议,帮助工程师有效解决信号失真、噪声干扰等常见问题,提升测量精度和系统可靠性。

weixin_26869081的博客 302

初学c++ 错误信息解释与解决

1, non-const static data member must be initialized out of line  解释:非const的静态值初始化必须在类外。 正确的写法: #include int static i = 0; class Base{ } /*******************************************************

上善若水 2万+

车载测试实战:adb logcat日志高效抓取与问题定位技巧

本文详细介绍了车载测试中adb logcat日志的高效抓取与问题定位技巧。作为车载测试的“第一现场”,adb logcat能实时、精准地抓取系统与应用日志,是定位应用崩溃、ANR及功能异常等问题的关键工具。文章从环境搭建、核心命令组合拳到实战分析与自动化脚本,提供了完整的操作指南,帮助测试人员快速掌握这一必备技能,大幅提升问题排查效率。

ii567的博客 1040

OBS技术深度剖析:从开源直播工具到专业制作引擎的进化之路

本文深入剖析了开源直播软件OBS的技术架构与发展历程。从2012年诞生至今,OBS已成长为直播领域的事实标准,其成功源于模块化设计和开源协作模式。文章详细解析了OBS的核心技术:1) 分层架构与插件系统,2) GPU加速的渲染管线,3) 智能音频处理,4) 多平台编码优化。同时探讨了虚拟摄像头、浏览器源等高级功能的实现原理,并提供了性能优化方案和硬件配置建议。随着AI、WebRTC等新技术发展,OBS将持续引领实时内容创作工具的创新,为开发者和创作者提供更强大的技术支持。

程序猿老樊的博客 327

C 与 C++ 的 static 关键字全解

1 前置知识 参考本系列的上一篇文章: C 与 C++ 的 extern 关键字全解_yihuajack的博客-优快云博客编译器的行为以 gcc/g++ 9.4.0 为准。1 前置知识1.1 声明、定义与初始化声明(声明式)= declarationextern int x;std::size_t numDigits(int number);class Widget;template<typename T>class GraphNode;定义(定义式)= definitionint x;s

Ayka的博客 1324

电磁场数值分析作业(西电)共5次【2021】

文章目录作业1作业2作业3作业4作业5 作业1 一个二维正方形(边长a=10mm)的静电场区域,电位边界条件如图所示(单位:V),求区域内的电位分布。要求用超松弛迭代法求解差分方程组进行计算。 clc clear close all hx=11; hy=11; v1=zeros(hy,hx); v1(hy,:)=ones(1,hx)*100; v1(1,:)=ones(1,hx)*50; for i=1:hy v1(i,1)=0; v1(i,hx)=100; end w=2/(1+

薛定谔的壳的博客 5074

条款45:C++(编译器)默默为我们完成和调用哪些函数

1,一个空的class何时不为空? 当C++编译器处理过它们之后. 2,如果你这么写: class Empty{}; 其意义相当于: class Empty { public: Empty(); Empty(const Empty& rhs); ~Empty(); Empty& operator=(cosnt Empty& rhs); Emtpy* oper...

wyjvip333的专栏 362

把 SAP Event Mesh 讲透:从事件驱动架构到 SAP BTP 落地实践

摘要: SAP Event Mesh是SAP BTP上的云端消息与事件服务,支持企业构建解耦、弹性的应用架构。它通过异步通信模式(如发布/订阅)解决传统同步集成的痛点,如系统紧耦合、链路脆弱等问题。核心能力包括事件驱动通信、可靠消息投递(支持至少一次送达)、与SAP生态深度集成(如S/4HANA事件扩展)以及混合环境支持。典型场景包括订单处理、库存同步等,发布方只需发出业务事件,订阅方按需消费,避免系统间直接依赖,符合Clean Core理念。两种关键模式为广播式的Publish/Subscribe和定向的

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 116

Android Framework 开发工程师职位深度解析与面试指南

摘要:博泰车联网科技(上海)股份有限公司招聘Android Framework开发工程师,负责车载系统的底层开发与优化。岗位要求5年以上经验,深入掌握Android Framework机制(WindowManager、PowerManager等模块),熟悉高通平台中间件架构及NDK/JNI开发,具备性能优化(启动时间、ANR处理)、OTA升级等能力。需熟练使用Android Studio、Git等工具,有车载开发经验者优先。工作内容包括Framework定制开发、问题排查及技术文档编写。

郑伟强dev的专栏 552

类中有引用需要注意——非静态的引用成员错误提示,不能使用默认的赋值运算符

我们知道,当我们我们没有定义赋值操作符时,编译器会生成一个默认的赋值操作符执行浅拷贝,就像默认构造函数一样是编译器默认生成的。而如果勒种有引用就需要注意一个大大的误区。我们知道引用在定义的时候就需要初始化,指定这个引用变量是哪个变量的别名,否则就会报错。当一个类中使用了引用但没有定义赋值操作符,会导致什么问题呢? #include<iostream> using namespace std;

无鞋童鞋的博客 2590

Python爬虫实战:实时爬取东方财富网股票行情

东方财富网实时行情(价格、涨跌幅、成交量等)K线图、分时图、技术指标市盈率、换手率、总市值等指标相比某些收费API,东方财富网页端接口不需要登录、免费、响应快、封装清晰,适合爬虫实践。东方财富网股票数据接口分析实时数据抓取与字段提取数据结构化处理自动化批量抓取多线程加速采集数据可视化展示支持存储为CSV/Excel/数据库。

2201_76125261的博客 1万+

Effective C++ Item 05: 了解C++默默编写并调用哪些函数

当你写了一个空的class时, 尽管你并没有声明构造函数和析构函数, 编译器还是帮你醉了 例如你写了一下代码定义了一个空的class: class Empty {}: 在经过编译器的处理之后, 实际等于如下代码: class Empty { public: Empty(){} ~Empty(){} Empty(const Emtpy& rhs){} Empty& opreator=(const Empty& rhs) {} }; 编译器为你自动生成了构造函数,析构函数,.

白熊的窝 118

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Effective C++ Item05 Note

//Effective C++ Item05 #include #include using namespace std; //声明一个empty class时,编译器会为它声明一个default构造函数,copy构造函数,一个copy assignment操作符和一个析构函数,所有这些函数都是public inline //编译器产出的析构函数是non-virtual的,除非base class

飘羽逸狂 436

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

linux 虚函数调用性能,C++对象布局及多态实现探索之虚函数调用

我们再看看虚成员函数的调用。类C041中含有虚成员函数,它的定义如下:struct C041{C041() : c_(0x01) {}virtual void foo() { c_ = 0x02; }char c_;};执行如下代码:C041 obj;PRINT_DETAIL(C041, obj)PRINT_VTABLE_ITEM(obj, 0, 0)obj.foo();C041 * pt = &...

weixin_39565910的博客 166

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C++对象布局及多态实现探索之虚函数调用

我们再看看虚成员函数的调用。类C041中含有虚成员函数,它的定义如下:struct C041{C041() : c_(0x01) {}virtual void foo() { c_ = 0x02; }char c_;};   执行如下代码:C041 obj;PRINT_DETAIL(C041, obj)PRINT_VTABLE_ITEM(obj, 0, 0)obj.foo();C041 * pt

fxpopboy的博客 607

pinduoduo.item_getAPI调用获取详情sku

HttpWebRequest则是.NET框架中更为强大的网络库,它可以进行请求头、请求体和响应内容的读写,并且支持代理、证书以及高级网络配置。无论是哪种语言,使用API接口时,需要将所需参数以指定格式组织(例如JSON或XML),并发送HTTP请求到API服务器,并接收服务器返回的响应内容,并按需进行解析和处理。1.PHP:curl库是PHP中使用最广泛的网络通信库之一,它支持HTTP/HTTPS协议,并且能够进行请求头、请求体和响应内容的读写。请求参数:num_iid=1620002566。

TinagirlAPI的博客 601

Effective C++ Item04 Note

//Effective C++ Item05 #include #include #include using namespace std; //array(来自C part of C++)不保证其内容被初始化,vector(STL part of C++)却由此保证 //C++对不同编译单元内的non-local static对象的初始化顺序并无明确定义 //如果某编译单元内的某个non-loc

飘羽逸狂 369

C++ :函数中无需改变传入参数的值时,定义时把 “Item & x ” 都改成 \“const Item & x\“

//f080204.h#ifndef f080204#define f080204#include#includeusing namespace std;class Date {int year, month, day;public: void set(int y, int m, int n);void set( string& s); bool isLeapYear();

dragoo1的专栏 414

IList.Item 属性

.NETFramework类库 IList.Item 属性 通过类实现时,获取或设置在指定的索引处的元素。 [C#] 在 C# 中,该属性为 IList 类的索引器。 [VisualBasic] Default Property I...

127

C++ 知识补充

向量(vector)是一个封装了动态大小数组的顺序容器(SequenceContainer)。跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,向量是一个能够存放任意类型的动态数组。C++中map提供的是一种键值对容器,里面的数据都是成对出现的,如下图:每一对中的第一个值称之为关键字(key),每个关键字只能在map中出现一次;第二个称之为该关键字的对应值。

weixin_47059239的博客 2131

multiset中元素排序比较函数的使用

  在《C++ Primer》关联容器的相关章节并没有介绍到multiset的多个构造函数的使用,在后来的章节中,涉及到一个问题的解决:如果multiset的元素类型是类类型,在不能使用默认的“<”操作符进行元素比较的时候,需要用到自定义的元素比较函数,将这个函数在multiset本身提供的构造函数中使用可以避免一些问题,具体详见《C++ Primer》第754页。但作为一个例子记下,作为一...

weixin_30709809的博客 398

在C++实现反射

<br />反射这个特性在C++中是没有的。所谓反射,自己的认为就是通过一个名字就可创建、调用、获取信息等一系列的操作,这个在脚本语言里面是比较常见的,COM组件也类似,知道个ID名,就可以做很多的工作了。<br />看看JAVA中的描述:<br />JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为JAVA语言的反射机制。<br />JAVA反射机制主要提供了以下功能:在运行时判

七彩狻猊 1万+

C++primer 第1章 快速入门

[引子]:某书店以文件形式保存每一笔交易。每笔交易记录某本书的销售情况,含ISBN,销售册数和销售单价。每一笔交易形如: 0-201-70353-x 4 24.99 第一个元素是ISBN,第二个元素是销售的册数,最后是销售单价。店主定期查看这个文件,统计每本书的销售册数,总销售收入以及平均售价。我们编程来进行计算: 【需要实现下面几点:】 定义变量 实现输入和输出 定义数据结构来保...

weixin_30421525的博客 199

中国工控网zggk.item_get API:电商行业数据获取的革新力量

随着信息技术的快速发展,电商行业已经深入渗透到各个领域,成为推动经济发展的重要力量。在这个过程中,数据获取成为了电商企业不可或缺的一环。中国工控网推出的zggk.item_get API,以其高效、准确的数据获取能力,成为了电商行业数据获取的革新力量。本文将详细探讨zggk.item_get API在电商行业中的应用价值、实现方式以及未来的发展趋势。一、zggk.item_get API概述及其在电商行业的应用价值。

api77的博客 1101
上一篇: Win7 环境下PyCharm 安装 注册 配置
下一篇: Item 06: 若不想使用编译器自动生成的函数,就该明确拒绝
onlyshi
博客等级 码龄12年 207粉丝 62原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值