栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

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

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

文章目录
  • 一、默认构造函数
    • 1、何时默认构造函数会自动生成
    • 2、编译器合成有用的构造函数四种情况
      • 2.1 类中内含带有默认构造的类成员
      • 2.2 带有默认构造的基类
      • 2.2 带有虚函数的类
      • 2.3 带有一个虚基类的类

一、默认构造函数 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.2 带有虚函数的类
- 当class声明/继承一个virtual function;
- 当class派生自一个继承串链,其中一个或更多的virtual base classes;
以上两种情况也会合成virtual constructor;
由于虚函数是通过虚表来进行存放,而虚表通过类中的vptr存储该地址,发生在编译期间,编译器必须给vptr设定初值,且放
置地址,这些都在构造函数中完成,故当函数有以上两种情况时,编译器会合成;
2.3 带有一个虚基类的类
编译器必须让虚基类在每个子类中的位置,能够在执行期准备好,在编译期不能够确定真正的类;
编译器会在构造中安插允许虚基类的执行器存取操作代码,故若没有构造函数,则编译器会自动合成;
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/847204.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号