C++对象模型-构造函数语意学

由于编译器会尽可能的为所有的警告和错误做出解释,但也因此导致了部分情况下的过度解析。

书中给的例子是编译器过度解析,使用了类型转换函数却隐藏了真正的错误。

    cin << intval;
    int temp = cin.operator int();
    temp << intval;

分析一下:

程序员的目的是实现读取输入,但是将 >> 写成了 <<, istream并没有重载 << 运算符,结果编译器按照 << 左移位来解析

要想实现左移位,又必须将cin转成整型。那么编译器会找istream有没有类型转换函数好将cin转成整型后再进行移位操作

如果找到了,那么,cin << intval; 正常执行了。并不报错。

所以为了避免这种转换发生,istream中使用了operator void*()来替换operator int()

隐式类型转换虽然会"暗地里"做一些转换操作,但这种机制的好处也是显而易见的。并且为了解决这个"暗地里"的隐式操作,提供了一个修饰符,即explicit,类型转换构造函数和类型转换函数声明前加上explicit关键字将阻止编译器隐式类型转换操作。任何尝试隐式转换的操作都会报错。

如下:

#include<iostream>
using namespace std;
class A
{
public:
    //explicit
    A(int a):m_a(a)
    {
        cout << "construct A from int" << endl;
    }
    //explicit
    operator int()
    {
        cout <<"convert A to int " << end;
        return m_a;
    }
public:
    int m_a;
};
int main(void)
{
    A a(5);//显式类型转换构造
    A b = 5;//隐式类型转换构造
    int i = a;//隐式类型转换函数
    return 0;
}

A a(5);总是正常的。

第一个explicit注释掉,A a(5);运行正常;去掉该注释,编译提示:类型转换失败

第二个explicit注释掉,int i = a;运行正常。 去掉该注释 编译提示:非法的存储类,即赋值失败。

原文地址:https://www.cnblogs.com/kuikuitage/p/9634788.html

时间: 2024-10-29 13:33:35

C++对象模型-构造函数语意学的相关文章

【深度探索C++对象模型】第二章 构造函数语意学(上)

第二章 构造函数语意学(The Semantics of Constructors) -- 本书作者:Stanley B.Lippman 一.前言 首先让我们来梳理一个概念: 默认构造函数(Default Constructor) : 是在没有显示提供初始化式时调用的构造函数.它由不带任何参数的构造函数,或是为所有形参提供默认实参的构造函数定义.如果定义的某个类的成员变量没有提供显示的初始化式时,就会调用默认构造函数(Default Contructor). 如果用户的类里面,没有显示的定义任何

【C++对象模型】构造函数语意学之二 拷贝构造函数

关于默认拷贝构造函数,有一点和默认构造函数类似,就是编译器只有在[需要的时候]才去合成默认的拷贝构造函数. 在什么时候才是[需要的时候]呢? 也就是类不展现[bitwise copy semantics]时,即不展现[逐位次拷贝]时,才会合成默认拷贝构造函数. 所谓的[逐位次拷贝],也就是简单的赋值,不管类内的数据成员是int还是char*指针,都是简单的赋值,这叫[逐位次拷贝]. 那什么请下不展现[逐位次拷贝]呢? 有四种情况: ①类中有一个类对象成员,而该类对象成员声明了一个默认拷贝构造函数

【C++对象模型】构造函数语意学之一 默认构造函数

默认构造函数,如果程序员没有为类定义构造函数,那么编译器会在[需要的时候]为类合成一个构造函数,而[需要的时候]分为程序员需要的时候和编译器需要的时候,程序员需要的时候应该由程序员来做工作,编译器需要的时候则由编译器来做工作. C++中,全局变量 / 对象的内存会被清零(如果类对象没有程序员定义的构造函数的时候), 而堆heap 或 栈stack上的变量或对象则不会被清零,其内存只取决于上一次这段内存的值. 而编译器什么情况下会为类合成默认构造函数呢?会在以下四种情况合成默认的构造函数: 1.类

深度探索C++对象模型 第二章构造函数语意学

在使用C++时,常常会好奇或者抱怨,编译器为我们做了什么事呢? 为什么构造函数没有为我初始化呢?为什么我还要写默认构造函数呢? 2.1 Default Constructor 的构造操作 如果没有声明默认构造函数,编译器会在需要的时候帮我们产生出来. 为了避免在多个地方被需要导致重复,则编译器将产生的构造函数声明为inline方式. class Foo {public:Foo(), Foo(int) }; class Bar {public: Foo foo;char *str;} Bar ba

构造函数语意学

C++参考手册告诉我们:default constructors -在需要的时候被编译器产生出来.关键字眼是:在需要的时候. 被谁需要? 做什么事? 当编译器需要它的时候(注意是编译器需要,而不是程序的需要),此外被合成出来的constructor只执行编译器所需要的行为(而不会执行程序所需要的行为,这个设计类的程序员负责). C++ standard 规定: 对于class X,如果没有任何user-declared constructor,那么会有一个default constructor被

《深度探索C++对象模型》第二章 | 构造函数语意学

默认构造函数的构建操作 默认构造函数在需要的时候被编译器合成出来.这里"在需要的时候"指的是编译器需要的时候. 带有默认构造函数的成员对象 如果一个类没有任何构造函数,但是它包含一个成员对象,该成员对象拥有默认构造函数,那么这个类的隐式默认构造函数就是非平凡的,编译器需要为该类合成默认构造函数.为了避免合成出多个默认构造函数,编译器会把合成的默认构造函数.拷贝构造函数.析构函数和赋值拷贝操作符都以内联的方式完成.一个内联含有具有静态链接,不会被文件以外者看到.如果函数不适合做成内联,就

深度探索C++对象模型之第二章:构造函数语意学之Default constructor的构造操作

C++新手一般由两个常见的误解: 如果任何class没有定义默认构造函数(default constructor),编译器就会合成一个来. 编译器合成的的default constructor会显示的设定“class内每一个data member的默认值” 一.编译器在哪种情况下才会合成默认构造函数: 对于未声明构造函数的类,只有在以下四种情况下编译器才会为它们合成默认构造函数: 类的成员有一个类对象(Member Class Object),且该成员含有默认构造函数(default Const

C++对象模型——Data 语意学(第三章)

第3章    Data 语意学 计算如下代码的sizeof结果: class X{}; class Y : public virtual X{}; class Z : public virtual X{}; class A : public Y, public Z{}; 上述X,Y,Z,A中没有任何一个 class 内含明显的数据,只表示了继承关系,所以认为每一个 class 的大小都是0.这样想法是错误的.即使 class X的大小也不为0. 一个空的 class 如: // sizeof(X

C++构造函数语意学——默认构造函数

概述 在 class 中,若程序员没有为该 class object 定义 default constructors,则编译器会根据需要产生一个 implicit default constructor,该 implicit default constructor 被认为是 trivial(无用的).那编译器怎样才能产生一个 nontrivial implicit default constructor?以下四个方面会产生nontrivial implicit default construct