本文所说的类型T均指UDT,非built-in类型

构造一个对象,有如下三种形式:

1。T a;
这个没什么好说的,调用default ctor来构造a
不过要注意的是,要么T就一个ctor也没有,编译器合成default ctor,即T::T()
如果T有手动添加的其他形式的ctor,但是没有T::T(),则此语句报错,因为编译器不再
为T合成default ctor
*注1,如果没有default ctor,但是有某个ctor的所有参数都有缺省值,则T a;也成立

2。T a(v);
这个语句显式用v作为参数调用T的某个最适合的可单参数调用的ctor来构造a
该语句形式被C++标准称为direct-initialization
这里强调两点,一个是显式,这说明这种方式构造a的话可以调用被explicit声明的ctor
第二点是最适合,这是由overload rules决定的,而不是那么想当然,示例代码如下
struct T
{
  T(){}
  T(int){}
  operator int(){return 0;}
private:
  T(T&){}
};
T foo() {return T();}
int main()
{
  T a;

T b(a);    // 编译出错,最适合的T(T&)不可访问,为private

T c(foo());// 编译成功,foo()返回的临时对象是rvalue,不能绑定到non-const引用
             // 因此T(T&)不是由overload rules选定的最适合ctor
             // 但是rvalue可以调用一次自定义隐式转换cast到int然后调用T(int)构造c
             // 也就是说,overload rules选择了T(int)

return 0;
}
这段代码说明,即使类型相同,调用的也不一定是copy ctor
如果有人怀疑T(T&)不是copy ctor,认为T(const T&)才是,请参阅C++标准12.8

3。T a = v;
该语句形式被C++标准称为copy-initialization,这个名称有很大的迷惑性,导致本人曾
一度认为该式语义上(稍后解释什么是语义上)必须要调用copy ctor
参照C++标准8.5/14,有这么一句话
If the destination type is a (possibly cv-qualified) class type:
--If the initialization is direct-initialization, or if it is 
  copy-initialization where the cv-unqualified version of the 
  source type is the same class as, or a derived class of, the 
  class of the destination, constructors are considered. The 
  applicable constructors are enumerated (13.3.1.3), and the 
  best one is chosen through overload resolution (13.3). The 
  constructor so selected is called to initialize the object, 
  with the initializer expression(s) as its argument(s). If no 
  constructor applies, or the overload resolution is ambiguous, 
  the initialization is ill-formed.
简单点说,上面的意思就是,如果T是UDT,在“copy-initialization且v的cv-
unqualified类型也为T(或者T的派生类)”的情况下,执行方式同
direct-initialization一样!
*注2,实际上该情况中的copy-initialization同direct-initialization还是有区别的,
*     C++标准指出,只有T a(v);的方式才是显式调用ctor,否则为隐式调用,后者要求
*     被选中的ctor不能被声明为explicit,否则编译出错
*---C++标准12.3.1
*     An explicit constructor constructs objects just like non-explicit
*     constructors, but does so only where the direct-initialization
*     syntax (8.5) or where casts (5.2.9, 5.4) are explicitly used.
C++标准还规定,如果非上述情况,则有
--Otherwise (i.e., for the remaining copy-initialization cases), 
  user-defined conversion sequences that can convert from the source
  type to the destination type or (when a conversion function is used) 
  to a derived class thereof are enumerated as described in 13.3.1.4, 
  and the best one is chosen through overload resolution (13.3). If the 
  conversion cannot be done or is ambiguous, the initialization is ill-formed.
  The function selected is called with the initializer expression as its 
  argument; if the function is a constructor, the call initializes a 
  temporary of the destination type. The result of the call (which is 
  the temporary for the constructor case) is then used to direct-initialize, 
  according to the rules above, the object that is the destination of 
  the copy-initialization. In certain cases, an implementation is permitted 
  to eliminate the copying inherent in this direct-initialization by 
  constructing the intermediate result directly into the object being 
  initialized; see 12.2, 12.8.
简单点说,就是语句T a = v;在当v的类型不同于T(也不是T的派生类)的时候,语义上
要先用v构造一个临时对象T(或者调用自定义转换隐式cast到T类型或者T的派生类型),
然后显式调用copy ctor来构造a
之所以强调语义上,是因为标准说了这个调用可以优化掉,但是语义存在
而强调显式,则说明copy ctor可以为explicit
此外需要强调的就是虽然标准在这里说构造了临时对象T(v)之后(或者是将v隐式转换
为类型T,static_cast<T>(v))再用direct-initialize直接构造a,整个语句总的执行
形式为T a(T(v));(static_cast<T>(v)用C语法也可记为T(v)),但是用T(v)所调用的
ctor只能是T的copy ctor,原因是编译器已经进行了一次自定义的隐式转换T(v),不能
再进行第二次,所以必须调用对T(v)直接参数匹配的ctor,这就是copy ctor
对上面的句子还有一个补充,就是派生类向基类的cast不算自定义隐式转换,是自动发
生的,所以还有一种选择就是T a(U(v));而U是T的派生类!最终调用的仍旧是copy ctor
示例如下
struct T
{
  T(){}
  T(int){}
  operator int(){return 0;}
private:
  explicit T(T&){}
};
int main()
{
  T a = T();  // 编译通过,相当于隐式调用T a(T());
              // 而重载规则选用了T(int),即T a(static_cast<int>(T()));
              // 如果T::T(int)声明为explicit,编译出错

T b = 0;    // 编译出错,copy ctor不能访问,虽然被优化这个调用,但是语义尚存

return 0;
}

下面再用一个示例补充说明
struct T
{
  T(int){}
  explicit T(const T&){}
};
void foo(T)
{
}
int main()
{
  foo(T(0)); // 编译出错,按照*注2,要求隐式拷贝给foo的参数
             // 相当于T t = T(0);

foo(0);    // 编译通过,用0构造一个临时对象T(0),然后显式拷贝给foo的参数
             // 相当于T t = 0;

return 0;
}
由于函数的按值传参和按值返回都是copy-initialization,所以会有如上的结果差异

T a(v);和T a = v;的区别相关推荐

  1. c语言求最多啤酒数,C语言,算法、动态规划:有一个箱子的容量为v(正整数,0=v=20000),同时有n个物品(0n=30),...

    满意答案 24k纯真爱l 2013.11.07 采纳率:42%    等级:12 已帮助:9552人 #include #define N 30 int xiangzi(int n ,int V ,i ...

  2. 抖音蓝V如何认证,蓝V号与普通号的区别?

    抖音蓝V如何认证,蓝V号与普通号的区别? 先说说抖音蓝V号和普通号的区别,两者之间最大的区别就是:抖音蓝V比普通号拥有更多的商业功能特权,更具有商业价值. 抖音蓝V有哪些功能特权呢? 1.外观功能 ( ...

  3. v.douyin.com/xxx v.ixigua.com/xxx抖音西瓜网址官方生成制作抖音西瓜缩短口令网址(仅供参考学习)

    抖音短链:https://v.douyin.com/2vGHjMu/(仅限抖音打开) 西瓜短链:https://v.ixigua.com/2oXjpMN/ v.douyin.com是抖音官方的接口,可 ...

  4. 金山发布毒霸V及网镖V新品 坚持高定价策略 (转)

    金山发布毒霸V及网镖V新品 坚持高定价策略 (转)[@more@]  6月3日晚,瑞星突然宣布,给用户和经销商让利2200万,并将单机版产品建议零售价调低30元,零售价格降至138元.同夜,江民宣布, ...

  5. 金山发布毒霸V及网镖V新品 坚持高定价策略

    6月3日晚,瑞星突然宣布,给用户和经销商让利2200万,并将单机版产品建议零售价调低30元,零售价格降至138元.同夜,江民宣布,将以38元的超低价位推出一款杀毒软件-KV江民杀毒王DOS杀毒伴侣.已 ...

  6. v+=e不等于v=v+e

    当v有副作用时,其实v+=e不等于v=v+e 计算v+=e只会求一次v的值,而计算v=v+e则会求两次v的值.在后一种情况下,对v求值可能引起的任何副作用也都会出现两次. a[i++]  +=  2; ...

  7. FFmpeg笔记--vcodec和-c:v,-acodec和-c:a的区别?

    在看ffmpeg命令的时候经常会看到有些地方使用--vcodec指定视频解码器,而有些地方使用-c:v指定视频解码器,那这两个有没有区别呢? ffmpeg的官方文档: -vcodec codec (o ...

  8. 求解!IDEA使用泛型V,K,V报红(报错),求大佬支招(已解决)

    public class LRULinkedHashMap extends LinkedHashMap {public V put(K key, V value){try {lock.lock();r ...

  9. 1.JAVA猜数字游戏: 一个类A有两个成员变量v、num,v有一个初值100。 定义一个方法guess,对A类的成员变量v,用num进行猜。 *如果num比v大则提示大了,反之则提示小了.

    思路:  * 1.创建一个类,定义两个成员变量v和num,v是固定值所以直接赋值,num是键盘录入的.  * 2.定义一个setNum类,将来通过对象调用将键盘录入接收的数据进行设置  * 3.创建一 ...

最新文章

  1. 043_Card卡片
  2. C语言试题八十二之输入小写字母,把小写字母转换成大写字母。
  3. Facebook 开源首个全卷积语音识别工具包 wav2letter++
  4. 论文|SDNE的算法原理、代码实现和在阿里凑单场景中的应用说明(附代码)
  5. 更新管理器_Excel2016数据透视表06:名称管理器实现透视表的动态更新
  6. 《研磨设计模式》builder生成器模式(golang)
  7. 语言学句法分析树形图怎么画_科学网—《泥沙龙笔记:漫谈自动句法分析和树形图表达》 - 李维的博文...
  8. iOS开发:如何使用ShareSDK让APP快速拥有分享功能
  9. 13部成功预知未来科技的科幻电影
  10. 修改电脑开机徽标教程
  11. 神经性疼痛的表现是什么,神经性疼痛常见部位是
  12. 最新学习笔记 2022-04-04
  13. idea的language level含义和module的language level自动跳到5
  14. 数据分析案例3 海量数据分析---根据Ip地址计算归属地的需求
  15. Openlayers利用kriging.js实现纯前端插值
  16. 完美的扎克伯格,倒霉的Facebook
  17. ldap+samba
  18. Java将字符串分割为数组
  19. NOIP 模板整理(多图预警╮(╯▽╰)╭)
  20. mysql 中文匹配_MYSQL-中文检索匹配与正则表达式

热门文章

  1. 【华为OD机试 2023最新 】 网上商城优惠活动(C++)
  2. 2023最新WSL搭建深度学习平台教程(适用于Docker-gpu、tensorflow-gpu、pytorch-gpu)
  3. 麻将--国标麻将番种图解 联众麻将规则图解
  4. 思维导图 XMind 闯关之路(第03关)插入图片
  5. vue中的for循环如何循环到到一定次数换行(歪门邪道)
  6. 码云新建仓库-代码上传
  7. 给网页添加动态视频背景 html+css
  8. Ueditor中增加迅雷下载支持
  9. 基于 HTML5 Canvas 的机房温度云图展示
  10. 用原生JS和CSS3做一个有趣的cube相册