这一章的时候,才明白什么是编译器的声明只会是一个默认的构造。这也解释了为什么同一似乎没有意义的界定,如果不还声明默认构造函数的意义。
Q:当编译器隐含定义了一个默认的构造函数。
答: 一个隐式声明的默认构造函数仅仅有在编译器须要的时候才隐式定义一个默认构造函数。仅仅有例如以下情况其才是必须的。
1、拥有虚成员函数的类。一个有虚成员函数的类一定会有一个non-trivial的构造函数。一个non-trivial的构造函数可能是用户定义的或者是编译器隐式定义的构造函数。而且它有责任为比如vptr的地址提供正确的初始化等。
2、带有Default Constructor 的 Member Class Object
3、带有Default Constructor的Base Class
4、带有一个Virtual Bass Class 的 Class
以上详情请见(深度探索C++对象模型)
Q:为什么编译器隐式声明Trivial构造函数即使他们从没有定义?
答:在一定条件下。编译器隐式声明一个默认构造函数但并不定义它。这种构造函数就是所谓的trivial。非常多c++程序猿对trivial成员函数的概念感到非常困惑。
当编译器知道某个函数不会被默认定义时到底是为什么这个编译器还要隐式的声明一个默认的构造函数呢?做这些有什么目的么?
首先第一件要牢记心中的事是隐式声明是概念上的,编译器并不会真正的在你的代码里面插入所谓的声明代码。更准确的说应该是编译器、连接器和程序表现的就像构造函数已经声明了。实际上,编译器仅仅是简单的在类的类型信息记录里面设置了一些bits用来表明它们所谓的类型有一个默认构造函数的声明。
如今我们回到最关键的问题上来吧,为什么要麻烦的有个隐式声明?毕竟C并不须要为它的struct或union提供这种机制。事实是隐式声明有一个契约似的规则。每个隐式声明就像合同里面的条款声明了一个确定的类怎么被使用。
当编译器隐式的声明这个特殊的成员函数,它授予某些授权给用户,相比之下,假设编译器不隐式声明成员函数,那就限制了用户对类的使用。考虑以下的代码:
struct Blocked { public: Blocked(const Blocked&); };
如今你肯定知道。由于copy-constructor的存在让编译器并不会隐式声明。
由于这个类没有隐式或显示的声明默认构造函数,你并不能像以下一样实例化一个类成员。
Blokced b; //error, no default constructor available Blocked *p = new Blocked; //error
没有隐式声明的机制。程序猿不得不为每个须要实例化的类手动的加入构造函数,拷贝构造函数,赋值函数和析构函数。以下的POD类型证明了这个观点:
struct Date { int day, month, year; };
编译器饮食声明了例如以下成员函数:
- A trivial default constructor
- A trivial copy constructor
- A trivial assignment operator
- A trivial destructor
这些声明能让你像以下一样使用Date:
Date d; //implicit declaration of default ctor and dtor allow this Date * pdate= new Date; //same here Date d2(d); //implicit copy ctor declaration allows this *pdate=d2; //implicit assignment operator declaration allows this delete pdate; //implicit dtor declaration allows this
trivial成员函数在C++编程里面是很重要的。为了让你明确它能为你省去多少麻烦,试着去显示声明它们:
struct Date { int day, month, year; private: ~Date(); //declared but not defined Date(const Date&); //ditto };
Date d; //error, no default ctor Date * pdate= new Date; //same error here Date d2(d); //error, no accessible copy ctor
如今上面的代码就不能通过编译了。