NotePublic/Software/Program/Language/Cpp/Cpp_默认构造方法.md

5.7 KiB
Raw Blame History

Cpp 默认构造方法

C++ 类可以有一个默认构造函数。在默认构造函数被需要的情况下,如果没有显式声明,则编译器自动为该类合成一个默认构造函数。当类只含有内置类型或复合类型的成员时,编译器是不会为类合成默认构造函数的。

合成默认构造函数总是不会初始化类的内置类型int 等)及复合类型(数组、结构体等)的数据成员。
分清楚默认构造函数被程序需要与被编译器需要,只有被编译器需要的默认构造函数,编译器才会合成它。

C++另一种类型为 类类型。

以下四种情况编译器需要默认构造函数:

  1. 含有类对象数据成员,该类对象类型有默认构造函数

    如果一个类没有任何构造函数,但是它含有一个类对象数据成员,且该类对象类型有默认构造函数,那么编译器就会为该类合成一个默认构造函数,不过这个合成操作只有在构造函数真正需要被调用的时候才会发生。

  2. 基类带有默认构造函数的派生类

    当一个类派生自一个含有默认构造函数的基类时,该类也符合编译器需要合成默认构造函数的条件。编译器合成的默认构造函数将根据基类声明顺序调用上层的基类默认构造函数。同样的道理,如果设计者定义了多个构造函数,编译器将不会重新定义一个合成默认构造函数,而是把合成默认构造函数的内容插入到每一个构造函数中去。

  3. 带有虚函数的类

    类带有虚函数可以分为两种情况:类本身定义了自己的虚函数 或 类从继承体系中继承了虚函数成员函数一旦被声明为虚函数继承不会改变虚函数的”虚性质“。这两种情况都使一个类成为带有虚函数的类。这样的类也满足编译器需要合成默认构造函数的类原因是含有虚函数的类对象都含有一个虚表指针vptr编译器需要对vptr设置初值以满足虚函数机制的正确运行编译器会把这个设置初值的操作放在默认构造函数中。如果设计者没有定义任何一个默认构造函数则编译器会合成一个默认构造函数完成上述操作否则编译器将在每一个构造函数中插入代码来完成相同的事情。

  4. 带有虚基类的类

    虚基类的概念是存在于类与类之间的是一种相对的概念。例如类A虚继承于类X则对于A来说类X是类A的虚基类而不能说类X就是一个虚基类。虚基类是为了解决多重继承下确保子类对象中每个父类只含有一个副本的问题。
    一个参考代码如下函数function参数pa的真正类型是可以改变的既可以把A对象指针赋值给pa也可以把对象指针赋值给pa在编译阶段并无法确定pa存储的i是属于A还是C的虚基类对象。为了解决这问题编译器将产生一个指向虚基类X的指针使得程序得以在运行期确定经由pa而存取的X::i的实际存储位置。这个指针的安插编译器将会在合成默认构造函数中完成同样的如果设计者已经写了多个构造函数那么编译器不会重新写默认构造函数而是把虚基类指针的安插代码插入已有的构造函数中。

class X  { public: int i; };
class A : public virtual X{ public:int j; };
class B : public virtual X{ public:double d; };
class C : public A, public B{ public: int k; };

void function(A *pa)
{
    pa->i = 1000;
}
int main()
{
    A *a= new A();
    C *c= new C();
    function(a);    //关注重点在这里
    function(c);    //关注重点在这里
    return 0;
}

默认构造函数有两种情况:

  1. 没有带明显形参的构造函数,即是 A() 的形式
  2. 为全部形参提供了默认实参的构造函数,即是 Aint a=0int b=0 的形式

你好

class A
{
public:
    A(int a=-1, bool b=true) { Va=a; Vb=b; } // 默认构造函数

    int Va; bool Vb;
}

int main()
{
    A a;    // 调用类A的默认构造函数
}

为了避免手动编写空默认构造函数C++11引入了显示默认构造函数的概念从而只需在类的定义中编写空默认构造函数而不需要在实现文件中提供其实现

// A.h
#ifndef A_H
#define A_H

class A{
public:
    A()=default;    //default
    A(int ii);
    void show()const;

private:
    int i;
};

#endif // A_H
// A.cpp
#include <iostream>
#include "tc.h"

using namespace std;

/*
A::A()
{
    // 不必给出其实现
};
*/

A::A(int ii)
{
    i=ii;
}

void A::show()const
{
    std::cout<<"this is A object!"<<std::endl;
};

int main()
{
    A a;
    a.show();
}

同样的C++还支持显式删除构造函数的概念。例如,你想定义一个类,这个类没有任何的构造函数,并且你也不想让编译器自动生成一个默认的空参数的构造函数,那么你就可以显式地删除默认构造函数。

// A.h
#ifndef A_H
#define A_H

class A{
public:
    A()=delete; //delete
    void show()const;

private:
    int i;
};

#endif // A_H
// A.cpp
#include <iostream>
#include "tc.h"

using namespace std;

/*
A::A()
{
    // 不必给出其实现
}

A::A(int ii)
{
    i=ii;
}*/

void A::show()const
{
    std::cout<<"this is A object!"<<std::endl;
}

int main()
{
    A a;
    a.show();
}

当类中含有不能默认拷贝成员变量时,可以禁止默认构造函数的生成,

myClass(const myClass&)=delete;             //表示删除默认拷贝构造函数,即不能进行默认拷贝
myClass & operatir=(const myClass&)=delete; //表示删除默认拷贝构造函数,即不能进行默认拷贝