首页 > 编程语言 >C/C++ 关于默认构造函数

C/C++ 关于默认构造函数

时间:2022-09-25 18:33:34浏览次数:86  
标签:初始化 struct Point int 默认 C++ 构造函数

前言:

在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起
其中 类名 必须指名当前类(或类模板的当前实例化),或在命名空间作用域或友元声明中声明时,必须是有限定的类名。    

类定义中的默认构造函数声明

  1. 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);
    }

    在这里插入图片描述

    • 隐式声明(或在其首个声明被预置)的默认构造函数,具有动态异常说明 (C++17 前)异常说明 (C++17 起)中所描述的异常说明。

其他

内置类型被认为具有默认构造函数和拷贝构造函数。但是,对于内置类型的未初始化的非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

相关文章

  • C++ 自学笔记 对象的初始化
    数组的初始化:  在C++中 struct≈Class;struct里面可以有函数。 默认构造函数:没有参数的构造函数就是默认构造函数 ......
  • 候捷-C++程序设计(Ⅱ)兼谈对象模型
    目录笔记参考学习目标转换函数与explicitpointer-likeclassesfunction-likeclasses模板template模板特化与偏特化模板模板参数引用(reference)关于虚指针(vptr)和虚表(vtbl)关......
  • C++自学笔记 构造与析构;
    构造与析构类不是实体;对象属于类;函数属于类;用不同的对象调用同一个类里面的函数的时候,函数知道是哪一个对象在调用它 关键字thisthis是一个指针 Pointa;a.pri......
  • 【以练促学】(C++基础语法)字符串篇
    (持续刷题持续更新...) 1.读取字符串cin>>arr;//输入字符串时,遇到空格或回车就会停止2. 读含空格字符串的3种方法:fgets(arr,100,stdin);cin.getline(arr,10......
  • C++ 引用注意的问题
    引用的对象不存在#include<iostream>usingnamespacestd;classA{public:A(intx){this->x=x;}~A(){};intget_x(){returnx;}private......
  • 【代码片段】Qt6.2.4 C++ 打开外部 CMD 窗口
    转载https://blog.csdn.net/fuhuixin7497/article/details/85126799正文打开了一个外部CMD窗口,并且主程序推出后该窗口不会关闭voidMainWindow::on_allPathCmdBtn......
  • C++ 避坑指南
    主要预防比赛时抱灵……可以用sizeprogram.exe来查看代码中的静态空间大小,能有效避免\(\text{MLE}\)的发生。在打完代码需要时刻注意题目中是否要开longlong,......
  • 我学习 C++ 运行时多态性的方法
    我学习C++运行时多态性的方法我的简短故事与实施原因。我希望你能明白我做了什么。我创建了一个设计文档。这有望帮助其他人理解我的解决方案。这是链接到员工工厂源代......
  • C++ bitset
    bitset可以更快的求大量位的表示和运算两个bitset<n>之间可以直接做与或非异或操作同时也可以使用set、count等位操作操作方法:1、https://blog.csdn.net/JAN6055/arti......
  • c++基础入门自学笔记总结3---结构体
    卷首闲言碎语:大风起兮云飞扬,又到周末兮打卡辽~不过这周并没有学到什么,就学习了结构体,不过学完结构体后c++的学习之旅就要暂时告一段落了,因为这几天也是在忙活于社团还有RM......