弄清C++在幕后为你所写、所调用的函数

C++ move()函数 要了解move函数首先弄清左值引用和右值引用。 左值、左值引用、右值、右值引用 1、左值和右值的概念 左值是可以放在赋值号左边可以被赋值的值;左值必须要在内存中有实体; 右值当在赋值号右边取出值赋给其他变量的值;右值可以在内存也可以在CPU寄存器。 一个对象被用作右值时,使用的是它的内容(值),被当作左值时,使用的是它的地址。 2、引用 引用是C++语法做的优化,引用的本质还是靠指针来实现的。引用相当于变量的别名。 ... 阅读详情

弄清C++在幕后为你所写、所调用的函数

一个空类什么时候不是空类? ---- 当C++编译器通过它的时候。如果你没有声明下列函数,体贴的编译器会声明它自己的版本。这些函数是:一个拷贝构造函数,一个赋值运算符,一个析构函数,一对取址运算符。另外,如果你没有声明任何构造函数,它也将为你声明一个缺省构造函数。所有这些函数都是公有的。换句话说,如果你这么写:

class Empty{};

和你这么写是一样的:

class Empty {
public:
  Empty();                        // 缺省构造函数
  Empty(const Empty& rhs);        // 拷贝构造函数

  ~Empty();                       // 析构函数 ---- 是否
                                  // 为虚函数看下文说明
  Empty&
  operator=(const Empty& rhs);    // 赋值运算符

  Empty* operator&();             // 取址运算符
  const Empty* operator&() const;
};

现在,如果需要,这些函数就会被生成,但你会很容易就需要它们。下面的代码将使得每个函数被生成:

const Empty e1;                     // 缺省构造函数
                                    // 析构函数

Empty e2(e1);                       // 拷贝构造函数

e2 = e1;                            //  赋值运算符

Empty *pe2 = &e2;                   // 取址运算符
                                    // (非const)

const Empty *pe1 = &e1;             //  取址运算符
                                    // (const)

假设编译器为你写了函数,这些函数又做些什么呢?是这样的,缺省构造函数和析构函数实际上什么也不做,它们只是让你能够创建和销毁类的对象(对编译器来说,将一些 "幕后" 行为的代码放在此处也很方便 ---- 参见条款33和M24。)。注意,生成的析构函数一般是非虚拟的(参见条款14),除非它所在的类是从一个声明了虚析构函数的基类继承而来。缺省取址运算符只是返回对象的地址。这些函数实际上就如同下面所定义的那样:

inline Empty::Empty() {}

inline Empty::~Empty() {}

inline Empty * Empty::operator&() { return this; }

inline const Empty * Empty::operator&() const
{ return this; }

至于拷贝构造函数和赋值运算符,官方的规则是:缺省拷贝构造函数(赋值运算符)对类的非静态数据成员进行 "以成员为单位的" 逐一拷贝构造(赋值)。即,如果m是类C中类型为T的非静态数据成员,并且C没有声明拷贝构造函数(赋值运算符),m将会通过类型T的拷贝构造函数(赋值运算符)被拷贝构造(赋值)---- 如果T有拷贝构造函数(赋值运算符)的话。如果没有,规则递归应用到m的数据成员,直至找到一个拷贝构造函数(赋值运算符)或固定类型(例如,int,double,指针,等)为止。默认情况下,固定类型的对象拷贝构造(赋值)时是从源对象到目标对象的 "逐位" 拷贝。对于从别的类继承而来的类来说,这条规则适用于继承层次结构中的每一层,所以,用户自定义的构造函数和赋值运算符无论在哪一层被声明,都会被调用。

我希望这已经说得很清楚了。

但怕万一没说清楚,还是给个例子。看这样一个NamedObject模板的定义,它的实例是可以将名字和对象联系起来的类:

template<class T>
class NamedObject {
public:
  NamedObject(const char *name, const T& value);
  NamedObject(const string& name, const T& value);

  ...

private:
  string nameValue;
  T objectValue;
};

因为NamedObject类声明了至少一个构造函数,编译器将不会生成缺省构造函数;但因为没有声明拷贝构造函数和赋值运算符,编译器将生成这些函数(如果需要的话)。

看下面对拷贝构造函数的调用:

NamedObject<int> no1("Smallest Prime Number", 2);

NamedObject<int> no2(no1);      // 调用拷贝构造函数

编译器生成的拷贝构造函数必须分别用no1.nameValue和no1.objectValue来初始化no2.nameValue和no2.objectValue。nameValue的类型是string,string有一个拷贝构造函数(你可以在标准库中查看string来证实 ---- 参见条款49),所以no2.nameValue初始化时将调用string的拷贝构造函数,参数为no1.nameValue。另一方面,NamedObject<int>::objectValue的类型是int(因为这个模板实例中,T是int),int没有定义拷贝构造函数,所以no2.objectValue是通过从no1.objectValue拷贝每一个比特(bit)而被初始化的。

编译器为NamedObject<int>生成的赋值运算符也以同样的方式工作,但通常,编译器生成的赋值运算符要想如上面所描述的那样工作,与此相关的所有代码必须合法且行为上要合理。如果这两个条件中有一个不成立,编译器将拒绝为你的类生成operator=,你就会在编译时收到一些诊断信息。

例如,假设NamedObject象这样定义,nameValue是一个string的引用,objectValue是一个const T:

template<class T>
class NamedObject {
public:
  // 这个构造函数不再有一个const名字参数,因为nameValue
  // 现在是一个非const string的引用。char*构造函数
  // 也不见了,因为引用要指向的是string
  NamedObject(string& name, const T& value);

  ...                          // 同上,假设没有
                               // 声明operator=
private:
  string& nameValue;           // 现在是一个引用
  const T objectValue;         // 现在为const
};

现在看看下面将会发生什么:

string newDog("Persephone");
string oldDog("Satch");

NamedObject<int> p(newDog, 2);      // 正在我写本书时,我们的
                                    // 爱犬Persephone即将过
                                    // 她的第二个生日

NamedObject<int> s(oldDog, 29);     // 家犬Satch如果还活着,
                                    // 会有29岁了(从我童年时算起)

p = s;                              // p中的数据成员将会发生
                                    // 些什么呢?

赋值之前,p.nameValue指向某个string对象,s.nameValue也指向一个string,但并非同一个。赋值会给p.nameValue带来怎样的影响呢?赋值之后,p.nameValue应该指向 "被s.nameValue所指向的string" 吗,即,引用本身应该被修改吗?如果是这样,那太阳从西边出来了,因为C++没有办法让一个引用指向另一个不同的对象(参见条款M1)。或者,p.nameValue所指的string对象应该被修改吗? 这样的话,含有 "指向那个string的指针或引用" 的其它对象也会受影响,也就是说,和赋值没有直接关系的其它对象也会受影响。这是编译器生成的赋值运算符应该做的吗?

面对这样的难题,C++拒绝编译这段代码。如果想让一个包含引用成员的类支持赋值,你就得自己定义赋值运算符。对于包含const成员的类(例如上面被修改的类中的objectValue)来说,编译器的处理也相似;因为修改const成员是不合法的,所以编译器在隐式生成赋值函数时也会不知道怎么办。还有,如果派生类的基类将标准赋值运算符声明为private,  编译器也将拒绝为这个派生类生成赋值运算符。因为,编译器为派生类生成的赋值运算符也应该处理基类部分(见条款16和M33),但这样做的话,就得调用对派生类来说无权访问的基类成员函数,这当然是不可能的。

以上关于编译器生成函数的讨论引发了这样的问题:如果想禁止使用这些函数,那该怎么办呢?也就是说,假如你永远不想让类的对象进行赋值,所以有意不声明operator=,那该怎么做呢?这个小难题的解决方案正是条款27讨论的主题。指针成员和编译器生成的拷贝构造函数及赋值运算符之间的相互影响经常被人忽视,关于这个话题的讨论请查看条款11。

 

一键抠图2:C/C++实现人像抠图 (Portrait Matting) 一键抠图2:C/C++实现人像抠图 (Portrait Matting),实现一键人像抠图,图像抠图,matting 阅读详情

相关推荐

抠像算法C++

视频抠像算法研究 抠蓝技术是指在摄影或摄像时,以蓝色为背景进行拍摄,在后期制作时使用特技机的“色键”将蓝色背景抠去,改换其他更理想的背景的技术,目的是使演员及道具看起来好像是在其他更理想的背景下拍摄的。 为了达到抠蓝的目的,在拍摄时,要求演员和道具不能使用蓝色。蓝色背景要求光线均匀,不能有阴影和色差。为了达到更换背景的目的,除了抠蓝,也常常“抠绿”,即采用绿色背景拍摄。无论抠蓝还是抠绿, 一般都要在摄影棚内进行,因为只有摄影棚才能把光线布置得尽可能地均匀。行业内把这种专门用于抠蓝的摄影棚叫做“蓝箱”。

Effective C++ 2e Item45

杂项进行高效的C++程序设计有很多准则,其中有一些很难归类。本章就是专门为这些准则而安排的。不要因此而小看了它们的重要性。要想写出高效的软件,就必须知道:编译器在背后为你(给你?)做了些什么,怎样保证非局部的静态对象在被使用前已经被初始化,能从标准库得到些什么,从何处着手深入理解语言底层的设计思想。本书最后的这个章节,我将详细说明这些问题,甚至更多其它问题。条款45: 弄清C++在幕后为你

lostmouse的专栏 1160

颜色抠像算法 抠图

目前主流的颜色抠像算法,很好的实线抠图,希望对大家有帮助!

条款45:弄清C++在幕后为你所写、所调用的函数

即,如果m是类C中类型为T的非静态数据成员,并且C没有声明拷贝构造函数(赋值运算符),m将会通过类型T的拷贝构造函数(赋值运算符)被拷贝构造(赋值)---- 如果T有拷贝构造函数(赋值运算符)的话。另一方面,NamedObject<int>::objectValue的类型是int(因为这个模板实例中,T是int),int没有定义拷贝构造函数,所以no2.objectValue是通过从no1.objectValue拷贝每一个比特(bit)而被初始化的。如果你没有声明下列函数,体贴的编译器会声明它自己的版本。

qq_41237850的博客 1106

抠像程序,从图片中抠出来人物

抠像程序,本程序是从图片中抠出来角色的程序,可以研究研究

抠图算法很不错

基于lazy snapping的抠图算法

条款 45: 弄清 C++在幕后为你所写、所调用的函数

如果你没有声明下列函数,体贴的编译器会声明它自己的版本。这些函数是:一个拷贝构造函数,一个赋值运算符,一个析构函数,一对取址运算符。另外,如果你没有声明任何构造函数,它也将为你声明一个缺省构造函数。所有这些函数都是公有的。 class Empty { public: Empty(); // 缺省构造函数 Empty(const Empty& rhs); // 拷贝构造函数 ~Empty();

lujiandong1的专栏 644

渐色抠图,视频抠图(通过HSV提取背景)

渐色抠图,视频抠图(通过HSV提取背景)

effective C++笔记之条款45: 弄清C++在幕后为你所写、所调用的函数

如果没有声明下列函数,编译器会声明它自己的版本。这些函数是:一个拷贝构造函数,一个赋值操作符,一个析构函数,一个取址运算符。另外,如果你没有声明任何构造函数,它也将为你声明一个缺省构造函数。所有这些函数都是公有的。当需要的时候需要,这些函数就会被生成。生成的这些函数中: 缺省构造函数和析构函数实际上什么也不做,它们只是让你能够创建和销毁类的对象。(33,M24)。生成的析构函数一般是非虚拟的

philips的专栏 2942

抠图代码(opencv)

可以对一个文件夹下的一系列图的同一个区域进行抠图

蓝布抠像算法

抠蓝技术是指在摄影或摄像时,以蓝色为背景进行拍摄,在后期制作时使用特技机的“色键”将蓝色背景抠去,改换其他更理想的背景的技术,目的是使演员及道具看起来好像是在其他更理想的背景下拍摄的。 为了达到抠蓝的目的,在拍摄时,要求演员和道具不能使用蓝色。蓝色背景要求光线均匀,不能有阴影和色差。为了达到更换背景的目的,除了抠蓝,也常常“抠绿”,即采用绿色背景拍摄。无论抠蓝还是抠绿, 一般都要在摄影棚内进行,因为只有摄影棚才能把光线布置得尽可能地均匀。行业内把这种专门用于抠蓝的摄影棚叫做“蓝箱”。

数学概念 | 旋转矩阵、欧拉角、四元数

旋转矩阵、欧拉角、四元数概念及相关运算;

NapoleonCoder的博客 772

抖音私信卡片私信名片的原理分析

简单说一下它的功能吧:抖音私信卡片,解决了客户封号严重、引流效率低的痛点,所以从去年到现在,依然是热销品。"抖音快手私信名片链接跳转"是2022年抖音快手引流最新技术,可以生成卡片链接,支持标题、描述、logo以及跳转落地页的完全自定义配置.支持微信公众号和微信号复制唤起微信客户端app添加,同时也支持任意链接落地页跳转提高粉丝引流转化率,关注转化率,引流转化率,安全绿色私信卡片功能1、跳转微信用户点击卡片,自动跳转微信界面,显示好友和群聊二维码2、跳转链接用户点击卡片,自动跳转到指定链接,支持任意链接。3

m0_71385839的博客 5190

Python自然语言处理 NLTK 库用法入门教程【经典】

@本文来源于公众号:csdn2299,喜欢可以关注公众号 程序员学府 本文实例讲述了Python自然语言处理 NLTK 库用法。分享给大家供大家参考,具体如下: 在这篇文章中,我们将基于 Python 讨论自然语言处理(NLP)。本教程将会使用 Python NLTK 库。NLTK 是一个当下流行的,用于自然语言处理的 Python 库。 那么 NLP 到底是什么?学习 NLP 能带来什么好处? ...

python函数基础教程 1万+

EffectiveC++第七章杂项学习笔记

条款45: 弄清C++在幕后为你所写、所调用的函数 当C++编译器通过它的时候。如果你没有声明下列函数,体贴的编译器会声明它自己的版本。这些函数是:一个拷贝构造函数,一个赋值运算符,一个析构函数,一对取址运算符。另外,如果你没有声明任何构造函数,它也将为你声明一个缺省构造函数。所有这些函数都是公有的。   条款50: 提高对C++的认识 C++最首要的目标在于: · 和C的兼容性。很多很

静。。。。。。。。。 513

Flutter版本升级踩坑实录:从3.27到3.35,我们是如何修复Impeller引擎导致的花屏问题的?

本文详细记录了团队在Flutter版本升级过程中遇到的Impeller引擎导致的花屏问题及解决方案。从问题诊断到最终升级至稳定版3.35,文章分享了排查步骤、升级策略和性能对比数据,为开发者提供了实用的参考经验。

weixin_26854555的博客 511

弄清C++在幕后为你做的

一个空类什么时候不是空类? ---- 当C++编译器通过它的时候。如果你没有声明下列函数,体贴的编译器会声明它自己的版本。这些函数是:一个拷贝构造函数,一个赋值运算符,一个析构函数,一对取址运算符。另外,如果你没有声明任何构造函数,它也将为你声明一个缺省构造函数。所有这些函数都是公有的。换句话说,如果你这么写:class Empty{};和你这么写是一样的:class Empty {p

shentian的专栏 819

告别两个电源模块!用UCD3138+四开关Buck-Boost,一个电路搞定电池充放电(附原理图分析)

本文详细介绍了采用UCD3138数字控制器和四开关Buck-Boost拓扑的双向DC/DC变换器设计,实现单一电路完成电池智能充放电管理。该方案显著降低BOM成本和PCB面积,提升系统效率至96.2%,适用于UPS、通信基站和储能系统,具有高效、紧凑和成本优势。

weixin_30256901的博客 397

机器视觉:9点标定的原理与实现

标定就是将机器视觉处理得到的像素坐标转换成实际项目中使用到的毫米坐标。简单说即使看看实际单位距离内有几个像素,如下图所示,10mm的距离内有222个像素,那像素坐标和实际的毫米坐标就有个比例关系了。

m0_49968063的博客 1万+
上一篇: VC6不支持模板函数在cpp文件中的实现
_CPU
博客等级 码龄22年 0粉丝 5原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值