前言:
在C++中,对于一个类,C++的编译器都会为这个类提供四个默认函数,分别是:
A() //默认构造函数 ~A() //默认析构函数 A(const A&) //默认拷贝构造函数 A& operator = (const A &) //默认赋值函数。
这四个函数如果我们不自行定义,将由编译器自动生成这四个缺省的函数,下面让我们来看看这四个函数(重点是后两个)。
一. 构造函数
构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户来调用它,而是在建立对象时自动执行。构造函数的功能是由用户定义的,用户根据初始化的要求设计函数体和函数参数,可以是一个,也可以是多个,可以把构造函数理解为重载的一种(函数名相同,不会返回任何类型,也不可以是void类型,参数类型个数可不同)。
构造函数的作用就是对当前类对象起到一个初始化的作用,类对象不像我们基本类型那样,在很多时候都需要初始化一些成员变量。
二、默认构造函数
先看下面代码
代码内容很简单,定义了一个包含成员x,y的类Point。在序列的地方可以使用这个类
虽然我们并没有定义Point类的构造函数,我们依然可以定义Point类的pt对象并使用它,其原因是编译器会自动生成一个缺省的构造函数,其效果相当于
但是,一旦添加了其他有参数的构造函数,编译器就不再生成缺省的构造函数了
C++11的解决方案
C++11允许我们使用=default
来要求编译器生成一个默认构造函数:
这样,我们就可以继续我们的美好生活了。
#include <stdio.h> struct Point { Point() = default; Point(int _x, int _y) : x(_x), y(_y){} int x; int y; }; int main() { Point point; printf("%d, %d", point.x, point.y); }
如果是自己编写的无参构造函数的话,就需要指定成员的构造方式。默认构造函数会对数据成员进行默认初始化,不需要另外指定。这样可以省去一些麻烦。
由于整数是内置类型,而整数成员的默认初始化是不初始化,所以本例中的x,y还是需要类内初始化。这是另一个话题。
定义
默认构造函数:是无参调用的构造函数,包括两种:
- 没有参数
- 每个参数有初始值
class Box { public: Box() { /*执行任何必需的默认初始化步骤*/} //所有参数都有默认值 Box (int w = 1, int l = 1, int h = 1): m_width(w), m_height(h), m_length(l){} ... }
调用场合
- 默认初始化:在不使用初始化器构造变量时执行的初始化。
- 值初始化:在以空初始化器构造对象时进行的初始化
说人话:如果构造函数在未指定参数或者提供了一个空初始化器列表,则会调用默认构造函数:
vector v1; vector v2{};
说明
默认构造函数是一种特殊的成员函数。如果未在类中声明任何构造函数,则编译器将提供隐式的inline默认构造函数
#include <iostream> using namespace std; class Box { public: int Volume() {return m_width * m_height * m_length;} private: int m_width { 0 }; int m_height { 0 }; int m_length { 0 }; }; int main() { Box box1; //调用编译器生成的构造函数 cout << "box1.Volume: " << box1.Volume() << endl; // Outputs 0 }
如果声明了任何非默认构造函数、编译器不会提供默认构造函数:
class Box { public: Box(int width, int length, int height) : m_width(width), m_length(length), m_height(height){} private: int m_width; int m_length; int m_height; }; int main(){ Box box1(1, 2, 3); Box box2{ 2, 3, 4 }; Box box3; // C2512: no appropriate default constructor available }
如果类中没有默认构造函数,将无法通过单独使用方括号语法来构造该类的对象数组。 例如,在前面提到的代码块中,框的数组无法进行如下声明:
Box boxes[3]; // C2512: no appropriate default constructor available
但是,可以使用一组初始值设定项列表来初始化 Box 对象的数组:
Box boxes[3]{ { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
语法
语法:
语法 | 说明 | o |
---|---|---|
类名 ( ) ; |
(1) | |
类名 :: 类名 ( ) 函数体 |
(2) | |
类名() = delete ; |
(3) | C++11起 |
类名() = default ; |
(4) | C++11起 |
类名 :: 类名 ( ) = default ; |
(5) | C++11起 |
其中 类名 必须指名当前类(或类模板的当前实例化),或在命名空间作用域或友元声明中声明时,必须是有限定的类名。 |
类定义中的默认构造函数声明
- struct Point { Point(){ x = 0; y = 0;}; int x; int y; };
类定义之外的默认构造函数的定义(该类必须包含一条声明1)
struct Point { Point(); //声明1 int x; int y; }; Point::Point(){ x = 10; y = 0; };
弃置的默认构造函数:若其被重载决议
所选择,则程序编译失败。
struct Point { Point() = delete ; // 错误:使用了被删除的函数‘Point::Point()’ int x; int y; };
预置的默认构造函数:即便其他构造函数存在,在某些情况下编译器会定义的隐式默认构造函数。
#include <stdio.h> struct Point { Point() = default; Point(int _x, int _y) : x(_x), y(_y){} int x; int y; }; int main() { Point point; printf("%d, %d", point.x, point.y); }
类定义之外的预置的默认构造函数(该类必须包含一条声明 (1))。这种构造函数被当做是用户提供的(user-provided)(见下文以及值初始化)。
struct Point { Point() ; // 错误:使用了被删除的函数‘Point::Point()’ int x; int y; }; Point::Point() = default;
隐式声明的默认构造函数
什么叫做隐式声明:用户没有声明、编译器声明
若不对类类型(struct、class 或 union)提供任何用户声明的构造函数,则编译器将始终声明一个作为其类的 inline public 成员的默认构造函数。
#include <stdio.h> struct Point1 { int x; int y; }; class Point2 { public: int x; int y; }; union Point3 { int x; int y; }; int main() { Point1 point1; Point2 point2; Point3 point3; printf("%d, %d\n", point1.x, point1.y); printf("%d, %d\n", point2.x, point2.y); printf("%d, %d\n", point3.x, point3.y); }
- C++11起,当存在用户声明的构造函数时,用户仍可以关键词 default 强制编译器自动生成原本隐式声明的默认构造函数。
#include <stdio.h> struct Point1 { Point1() = default; // 必须,当用户最定义了有参构造函数时编译器不会自己生成默认构造函数 Point1(int _x, int _y) : x(_x), y(_y){} int x; int y; }; class Point2 { public: Point2() = default; // 必须,当用户最定义了有参构造函数时编译器不会自己生成默认构造函数 Point2(int _x, int _y) : x(_x), y(_y){} int x; int y; }; union Point3 { Point3() = default; // 必须,当用户最定义了有参构造函数时编译器不会自己生成默认构造函数 Point3(int _x) : x(_x){} int x; int y; }; int main() { Point1 point1; Point2 point2; Point3 point3; printf("%d, %d\n", point1.x, point1.y); printf("%d, %d\n", point2.x, point2.y); printf("%d, %d\n", point3.x, point3.y); }
其他
内置类型被认为具有默认构造函数和拷贝构造函数。但是,对于内置类型的未初始化的非static变量,其默认构造函数不会被调用。内置整数类型的默认值为0,浮点数默认值为0.0,指针类型的默认值为nullptr
void f(){ int a0; //未初始化 int a2{}; //初始化为0 double d1{}; //初始化欸0.0 char *p{}; //p变成nullprt int *p1 = new int; //未初始化 int *p2 = new int{}; //初始化为0 }
内置类型的构造函数最常用于模板参数:
template<typename T> struct Handle{ T * p; Handle(T *pp = new T{}) :p{pp}{} }; Handler<int> px; //会生成int{} --- 初始化为0
引用和const必须被初始化。因此,一个包含这些成员的类不能默认构造,除非程序员提供了类内成员初始化器或者定义了一个默认构造函数来初始化它们
int glob{9}; struct X{ const int a1{7}; //ok const int a2; //错误:需要一个用户自定义构造函数 const int & r{9}; //ok int& r1{glob}; //ok int& r2; //错误,需要一个用户自定义构造函数 }; X x; //错误:X没有默认构造函数
实例
class A { public: A(); //没有参数 }; class B { public: explicit B(int x = 1, bool b = true); //每个参数有初始值 //explicit:阻止执行隐式转换,但是可以显示类型转换 }; class C { public: explicit C(int c); //非默认构造函数 };
struct A { int x; A(int x = 1): x(x) {} // 用户定义默认构造函数 }; struct B: A { // 隐式定义 B::B(),调用 A::A() }; struct C { A a; // 隐式定义 C::C(),调用 A::A() }; struct D: A { D(int y): A(y) {} // 不会声明 D::D(),因为存在另一构造函数 }; struct E: A { E(int y): A(y) {} E() = default; // 显式预置,调用 A::A() }; struct F { int& ref; // 引用成员 const int c; // const 成员 // F::F() 被隐式定义为弃置 }; int main() { A a; B b; C c; // D d; // 编译错误 E e; // F f; // 编译错误 }
搬运原文 C/C++编程:默认构造函数_OceanStar的学习笔记的博客-CSDN博客_c++默认构造函数
标签:初始化,struct,Point,int,默认,C++,构造函数 From: https://www.cnblogs.com/slowlydance2me/p/16728436.html