`
luliangok
  • 浏览: 778748 次
文章分类
社区版块
存档分类
最新评论

隐式创建默认构造函数的迷惑(一)

 
阅读更多

隐式创建默认构造函数的迷惑(一)

《深度探索C++对象模型》读书笔记

飘飘白云

《深度探索C++对象模型》(以后简称《深探》)书中如此给新手提醒:

C++新手一般有两个常见的误解:


1,任何class如果没有定义 default constructor ,就会被合成出一个。


2,
编译器合成出来的 default constructor 会明确设定 class 内每一个 data member 的默认值”。


如你所见,没有一个是真的!”。

看了这一段,是不是觉得大学里教C++的就是糊弄小朋友的,如果不是见到这段话,我还会傻乎乎地相信,每个类如果没有定义默认构造函数,就会自动创建一个,并使用“零值”初始化数据成员。

先看个例子:

#include <iostream>


using namespace std;



class Foo


{


public:


int val;



// Foo()


// {


// };


virtual ~Foo()


{


};



protected:


private:


};



int main()


{


Foo bar ;


if ( bar.val == 0)


{


cout << "Data member val has been initialized to 0" << endl;


}


else


{


cout << "Data member val hasn't been initialized to 0" << endl;


}


}

VS下编译运行输出:Data member val hasn't been initialized to 0 如果把被屏蔽的那个空构造函数恢复,输出结果就是另外一回事了。

那么到底在什么情况下,C++编译器会为我们创建默认构造函数,并初始化数据成员呢?C++ StandardISO-C++95〕里面这么说的:

“对于 class X ,如果没有任何用户声明的构造函数,那么会有一个默认构造函数被隐式声明出来…… 一个被隐式声明出来的默认构造函数将是一个没什么用的(trival)构造函数。”

这里所说的“没什么用的(trival)”是指仅仅是为了编译器编译的需要,而不是为了程序需要(比如变量必须初始化)而创建这么一个构造函数。看了上面这段话,感觉前面的提醒似乎有点不对,呵呵,后面还有说明:

在四种情形下,“编译器必须为未声明constructorclasses 合成一个 default constructor”,C++标准把那些合成物成为 隐式的有用的(nontrivaldefault constructor,它们只能满足编译器的需要。


在这四种情况之外而有没有声明任何 constructor classes ,拥有的是隐式的没什么用的(trivialdefault constructor,实际上它们并不会被合成出来。

下面我们依次来说明这四种情形A,B,CD<待续>

情形A:拥有成员对象,并且这个成员对象所属的类拥有默认构造函数。

一个类没有任何构造函数,但是它内含有一个成员对象,而这个成员对象有默认构造函数,那么编译器就会在必要的时候为这个类隐式合成一个有用的(nontrival)构造函数。

还是来看代码说的清楚些:



#include
<iostream>


using namespace std;


class Foo


{


public:


// Foo()


// {


// cout << "Default constructor of Foo!";


// };



Foo(int a){


iFooVal = a;


cout << "Common constructor of Foo!";


};


~Foo(){



};


int iFooVal;


};



class Bar


{


public :


Foo foo;


int iBarVal;


~Bar()


{


};


};



int main()


{


Bar bar;



if (bar.foo.iFooVal == 0)


{


cout << "Member data of foo has been initialized!"<< endl;


}



if (bar.iBarVal == 0)


{


cout << "Member data of bar has been initialized!"<< endl;


}



}

在这段代码里,我把成员对象Foo的默认构造函数屏蔽了,按照上面的解释,应该是会报错,因为类Bar不会合成一个隐式的有用的默认构造函数。编译运行,看看编译器怎么说:

error C2512: 'Bar' : no appropriate default constructor available

呵呵,不出所料!如果我们恢复Foo的默认构造函数Foo(),则编译运行输出:

Default constructor of Foo!

注意:BarFoo的数据成员并没有因此而初始化为0!

下来我们来深入探索下在Foo有默认构造函数的情形下,声明Bar对象时被合成的那个隐式有用的构造函数做了些什么:

它会按照有显式默认构造函数的成员对象在类中声明的顺序依次调用这些成员对象的显式默认构造函数,除此之外它什么也不做。

那么为Bar合成的那个隐式构造函数就应该看起来象这个样子:

inline Bar::Bar()


{


foo.Foo::Foo();
}

分享到:
评论

相关推荐

    使用隐式Intent,创建一个启动器

    使用隐式Intent,创建一个启动器应用来替换Android默认的启动器应用

    画隐式函数的Matlab程序

    该程序适用于用matlab画隐式函数的图,只需要输入函数表达式即可。很方便实用!

    C++中何时调用复制构造函数

     复制构造函数既可以自己定义又可以像默认构造函数一样被编译器隐式调用。但大多数时候,特别是类中有指针成员的时候要实现深复制,避免浅复制时,需要自己定义复制构造函数。  那么我们定义的复制构造函数什么...

    DeepMLS:用于3D重构的深层隐式移动最小二乘函数

    DeepMLS:用于3D重建的深层隐式移动最小二乘函数该存储库包含本文的实现: 用于3D重构的深层隐式移动最小二乘函数 世林刘,,,,。 如果您发现我们的代码或书面文件有用,请考虑引用@inproceedings { Liu2021MLS , ...

    C#私有构造函数使用示例

    本文主要介绍了C#私有构造函数使用方法,私有构造函数是一种特殊的实例构造函数。它通常用在只包含静态成员的类中。如果类具有一个或多个私有构造函数而没有公共构造函数,则其他类(除嵌套类外)无法创建该类的实例

    c++基础语法:构造函数与析构函数

    构造函数用来构造一个对象,主要完成一些初始化工作,如果类中不提供构造函数,编译器会默认的提供一个默认构造函数(参数为空的构造函数就是默认构造函数) ;析构函数是隐式调用的,delete对象时候会自动调用完成...

    c++基础语法:构造函数初始化列表

    1.必须这样做:如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,而没有默认构造函数,这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,如果...

    JSP语法之隐式对象详解

    了解JSP 隐式对象的分类和组成 能够运用隐式对象进行JSP 编程 理解Page、Request、Session 和Application 范围的区别

    matlab.rar_matlab隐式_一维热方程_热传导 matlab_热传导 隐式_隐式差分

    一维热传导方程的MATLAB计算,使用隐式差分格式,追赶法计算

    Delphi XE7 隐式调用案例

    Delphi XE7 隐式调用案例,欢迎各位下载调试- -

    tessellation:Tessellation 是一个用于 3d 曲面细分的库,例如它将根据体积的任何隐式函数创建一组三角形

    镶嵌 Tessellation 是一个用于 3d 曲面细分的库,例如,它将根据体积的任何隐式函数创建一组三角形。 Tessellation 实现了 。例子创建一个单位球体并细分它: use nalgebra as na;//!struct UnitSphere { bbox : ...

    PHP中构造函数和析构函数解析

    Note: 如果子类中定义了构造函数则不会隐式调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()。如果子类没有定义构造函数则会如同一个普通的类方法一样从父类继承...

    一维抛物问题的隐式算法

    一维抛物问题的隐式算法,使用N-T差分格式,使用不动点迭代求解大型稀疏方程组,供学习和交作业参考。时间和空间步长可调

    C++初始化函数列表详细解析

    在以下三种情况下需要使用初始化成员列表: ...若没有提供显示初始化式,则编译器隐式使用成员类型的默认构造函数,若类没有默认构造函数,则编译器尝试使用默认构造函数将会失败。(也就是这三种情况

    Android中使用隐式方式打开一个新的Activity

    Android中使用隐式方式打开一个新的Activity!

    C++中explict关键字用法

    c++规定:对于可能只需传一个参数的默认构造函数,都定义了一种隐式调用。 注意:只需传一个参数不仅指的是只有一个参数的默认构造函数,也指那些包含了定义了参数默认值的那些默认构造函数。 举例说明: class ...

    动态链接库DLL的(隐式和显式)的创建和使用

    资源包括一个创建DLL的工程,一个使用DLL的工程,共俩个工程。...附带一个说明文档,分为静态(隐式)链接方式和动态(显式)链接方式详细介绍了DLL的创建以及使用方式。 简单明了,一学包会,不坑爹。

    创建隐式事务管理数据库更新

    创建隐式事务管理数据库更新

    C++/JAVA/C#子类调用父类函数情况总结

    —–基类有默认构造函数时,可以在子类不写,则隐式调用 —–基类无/有默认构造函数时,在子类构造函数初始化列表处调用,则显示调用 基类类名(参数) class Base { public: Base(int b) : m_b(b) { } private...

Global site tag (gtag.js) - Google Analytics