C++【对象模型】|【02】构造函数何时才会被编译器自动生成?

索引

C++【对象模型】| 【01】简单了解C++对象模型的布局
C++【对象模型】|【02】构造函数何时才会被编译器自动生成?
C++【对象模型】|【03】拷贝构造是如何工作的,何时才会用到呢?
C++【对象模型】 | 【04】程序在内部被编译器如何转化?
C++【对象模型】 | 【05】类与类之间各种关系下对数据成员的存取、绑定、布局
C++【对象模型】| 【06】类中各种函数的刨析
C++【对象模型】| 【07】构造、析构、拷贝做了哪些事?
C++【对象模型】| 【08】类在执行期会处理哪些事呢?
C++【对象模型】| 【09】类模板、异常处理及执行期类型识别

一、默认构造函数

1、何时默认构造函数会自动生成

当类没有提供默认构造时,如果编译器需要它,则将会为其添加上;如果是程序的需要,则需要我们手动为它添加;
- 并不是没有声明默认构造时,编译器就自动生成;只在编译器真正需要的时候;

如何区分编译器需要还是程序需要

当使用`foo f;`创建一个对象时,
- 【编译器】由于类中没有提供默认构造函数,编译器会自动为其生成使之能被创建成功;
- 【程序】类中的数据成员初始化交给构造函数,当想要默认的构造函数能够初始化数据成员(a)时,则我们需要手动提供;
class foo{
public:
	void func(); 
private:
	int a;
}

2、编译器合成有用的构造函数四种情况

2.1 类中内含带有默认构造的类成员

当一个类内含一个类成员(带默认构造),此时编译器需要为类合成一个默认构造函数(在真正需要被调用时才发生);
class B{}
class A{ 
private:
	B b;
}

编译器(不同的文件)如何避免合成多个默认构造?

其编译器合成的函数都是按内联的方式完成,具有静态链接,不会被文件外使用、看到;

案例

class Foo { public: Foo(), Foo(int) }
class Bar { public: Foo foo; char *str; }

void func() {
	Bar bar;
}
【如果没有Bar没有提供默认构造】
当创建一个Bar对象时,由于内含一个Foo成员,其foo必须要在它构造的时候初始化;
而Bar没有提供默认构造,故编译器需要为它生成一个能够调用Foo的默认构造来处理成员Bar::foo;【编译器责任】
但生成的默认构造不为str做初始化【程序员责任】
===> 编译器合成的默认构造
inline Bar::Bar() { foo.Foo::Foo() }

【如果Bar提供默认构造】
====> Bar::Bar() { str = 0; }
此时程序的需求被满足,但没有对foo进行初始化提供,而此时应该有默认构造,故编译器不会再次生成默认构造;
那编译器会怎么做呢?
编译器会将初始化foo的代码插入在默认构造的用户代码前(str之前);
如果类中内含多个其他类,则将按照声明顺序将其插入;

2.2 带有默认构造的基类

【当子类没有默认构造】
当继承的基类含有默认构造时,若子类没有默认构造,则编译器会自动生成【用来调用基类的构造函数】;
【子类提供构造函数】
当子类提供构造函数但没有默认构造,则编译器会扩张每一个构造函数(添加基类的默认构造代码),不会合成新的默认构造;

【注意】成员类的调用次序在继承后;
class A{
public:
    A() { cout << "A" << endl; }

    ~A() { cout << "~A" << endl; }
};

class B {
public:
    B() { cout << "B" << endl; }
    ~B() { cout << "~B" << endl; }
};

class C : public A{
public:
    C() { cout << "C" << endl; }
    C(int v) {}
private:
    B b;
};

int main() {
    C c;
    cout << "------------" << endl;
    C cc(1);
    cout << "------------" << endl;
    return 0;
}

在这里插入图片描述

2.3 带有虚函数的类

- 当class声明/继承一个virtual function;
- 当class派生自一个继承串链,其中一个或更多的virtual base classes;
以上两种情况也会合成virtual constructor;
由于虚函数是通过虚表来进行存放,而虚表通过类中的vptr存储该地址,发生在编译期间,编译器必须给vptr设定初值,且放
置地址,这些都在构造函数中完成,故当函数有以上两种情况时,编译器会合成;

2.4 带有一个虚基类的类

编译器必须让虚基类在每个子类中的位置,能够在执行期准备好,在编译期不能够确定真正的类;
编译器会在构造中安插允许虚基类的执行器存取操作代码,故若没有构造函数,则编译器会自动合成;
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jxiepc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值