C++:默认构造函数

一、类的默认成员函数

  • 当你定义一个空类时,编译器并不会真的"空手而归"。它会自动为你生成6个(C++98)或更多(C++11后)特殊的成员函数。这些函数被称为默认成员函数。
  • 他们分别是:
函数 作用
默认构造函数 初始化对象
析构函数 清理对象资源
拷贝构造函数 用已有对象初始化新对象
赋值运算符重载 将已有对象赋值给另一对象
移动构造函数(C++11) 用临时对象"转移"资源
移动赋值运算符(C++11) 临时对象赋值
  • 如果没有主动声明这些函数,编译器就会自动生成一个默认版本,即为默认成员函数。

二、构造函数的基本概念

  • 构造函数是类中一种特殊的成员函数,它在对象创建时自动调用,用于初始化对象的成员变量。
构造函数的规则:
  • 函数名与类名完全相同
  • 没有返回值
  • 可以重载(可以有多个参数不同的构造函数)
  • 对象创建时自动执行

三、默认构造函数的含义

  • 默认构造函数是指可以无实参可调用的构造函数。它包括两种情况:
    • 程序员定义的默认构造函数:
      • 程序员定义的无参构造函数。
      • 程序员定义的全缺省参数的构造函数。
    • 程序员没有定义构造函数,编译器自动生成的隐式默认构造函数。
cpp 复制代码
class Student {
public:
    // 无参构造函数
    Student() {
        name = "无名";
        age = 0;
    }
private:
    string name;
    int age;
};
cpp
class Point {
public:
    // 全缺省参数的构造函数(也是默认构造函数)
    Point(int x = 0, int y = 0) : x(x), y(y) {}
private:
    int x, y;
};

四、编译器自动生成的默认构造函数

  • 若程序员没有实现构造函数,编译器会为你生成一个隐式默认构造函数。
cpp 复制代码
class Dog {
    string name;
    int age;
    // 编译器自动生成 Dog() {}
};
这个隐式构造函数会做什么?
  • 对于内置类型(int, char, 指针等):不做任何初始化(不同编译器效果不同)。
  • 对于自定义类型成员:调用它们各自的默认构造函数。
cpp 复制代码
#include <iostream>
using namespace std;

class A {
public:
    A() { cout << "A的构造函数" << endl; }
};

class B {
    int x;      // 内置类型,不会初始化(垃圾值)
    A a;        // 类类型,会调用A的默认构造函数
};

int main() {
    B b;   // 输出:A的构造函数(x保持随机)
}
一旦你实现了构造函数,编译器就不再生成默认构造函数
cpp 复制代码
class Student {
public:
    Student(string n) { name = n; }  // 自定义构造函数
private:
    string name;
};

int main() {
    Student s1("张三");  // 正确
    // Student s2;       // 错误!没有默认构造函数可用
}
如果你既需要带参构造,又需要无参构造,需要手动提供默认构造函数。

五、默认构造函数的用途

1. 定义对象而不初始化
cpp 复制代码
class Array {
    int* data;
public:
    Array() { data = nullptr; }  // 允许定义空数组对象
};
Array arr;   // 调用默认构造
2. 作为容器元素的默认构造要求

STL容器(如vector)在扩容或创建元素时,经常需要元素的默认构造函数。

cpp 复制代码
vector<Student> v(10);  // 需要Student有默认构造函数
3. 继承体系中基类的初始化

派生类构造函数会自动调用基类的默认构造函数(如果基类没有默认构造,派生类必须显式调用基类的带参构造)。

六、什么时候需要自定义默认构造函数?

情况 是否需要
类没有指针成员,且成员都有合理的默认值 不需要,编译器生成即可
成员中需要分配资源 需要(在构造中分配并初始化)
需要给成员变量设置特定的初始值 需要
类有自定义的带参构造,但仍需无参创建对象 需要
cpp 复制代码
class MyString {
    char* buf;
public:
    // 自定义默认构造:给指针一个安全的初始值
    MyString() {
        buf = new char[1];
        buf[0] = '\0';
    }
};

七、C++11 的改进:default 和 delete

C++11允许你显式要求编译器生成默认版本,或禁止某个构造函数。

cpp 复制代码
class Widget {
public:
    Widget() = default;           // 手动要求编译器生成默认构造
    Widget(const Widget&) = delete; // 禁止拷贝构造
};

八、一个完整的例子

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

class Book {
public:
    // 默认构造函数
    Book() {
        title = "未命名";
        price = 0.0;
        cout << "调用默认构造函数" << endl;
    }
    // 带参构造函数(不是默认构造)
    Book(string t, double p) : title(t), price(p) {
        cout << "调用带参构造函数" << endl;
    }
    void print() {
        cout << "书名:" << title << ",价格:" << price << endl;
    }
private:
    string title;
    double price;
};

int main() {
    Book b1;              // 调用默认构造
    Book b2("C++教程", 59.9); // 调用带参构造
    b1.print();
    b2.print();
    return 0;
}

输出:
text
调用默认构造函数
调用带参构造函数
书名:未命名,价格:0
书名:C++教程,价格:59.9
相关推荐
小欣加油3 小时前
leetcode994 腐烂的橘子
数据结构·c++·算法·leetcode·bfs
.千余4 小时前
【C++】手写双向链表:list容器模拟实现
开发语言·c++·笔记·学习·其他
liulilittle4 小时前
过冲:拥塞控制的呼吸与盲行
linux·网络·c++·tcp/ip·计算机网络·tcp·通信
小欣加油4 小时前
leetcode2574 左右元素和的差值
数据结构·c++·算法·leetcode·职场和发展
weixin_461769405 小时前
通过数组和队列构造二叉树方法(用于算法测试),C++ vector不能直接使用null
数据结构·c++·算法·vector·nullptr·null
千寻girling5 小时前
一周没跑步了 ,今日跑步 5KM , 哑铃+健身 20min , 俯卧撑 30 个 ;
数据结构·c++·python·算法·leetcode·职场和发展·线性回归
坚果派·白晓明5 小时前
鸿蒙PC三方库使用:使用 AtomCode + Skills 自动完成鸿蒙化三方库spdlog集成
c++·华为·ai编程·harmonyos·skills·atomcode·c/c++三方库
玖玥拾5 小时前
C/C++ 基础笔记(九)联合、枚举及文件操作
c语言·c++·文件操作·枚举·联合
liulilittle5 小时前
拥塞控制:公平性的不可能三角
网络·c++·网络协议·tcp/ip·计算机网络·tcp·通信