C++学习笔记16:构造函数

目录

一、为什么需要构造函数?

二、什么是构造函数?

三、构造函数不是创建对象

四、带参数的构造函数

五、构造函数支持重载

六、默认构造函数

[1. 无参构造函数](#1. 无参构造函数)

[2. 全缺省构造函数](#2. 全缺省构造函数)

七、无参构造和全缺省构造不能同时存在

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

九、自己写了构造函数后,编译器还会生成默认构造函数吗?

十、小结


一、为什么需要构造函数?

在C++中,我们用类创建对象。

例如定义一个日期类:

cpp 复制代码
class Date {
	public:
		void Print() {
			cout << _year << "-" << _month << "-" << _day << endl;
		}
	
	private:
		int _year;
		int _month;
		int _day;
};

如果直接创建对象:

cpp 复制代码
Date d;
d.Print();

这时 _year、_month、_day没有被初始化,可能是随机赋值。

所以我们需要一种机制,在对象创建时自动完成初始化。

这就是构造函数的作用。


二、什么是构造函数?

构造函数时类中的一种特殊成员函数。

它的作用是:

在对象创建时自动调用,用来初始化对象。

构造函数的基本特点:

cpp 复制代码
1. 函数名和类名相同;
2. 没有返回值;
3. 对象实例化时自动调用;
4. 构造函数可以重载。

例如:

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

class Date {
	public:
		Date() {
			_year = 2024;
			_month = 1;
			_day = 1;
		}
		
		void Print() {
			cout << _year << "-" << _month << "-" << _day << endl;
		}
	
	private:
		int _year;
		int _month;
		int _day;
};

int main() {
	Date d;
	d.Print(); 
	
	return 0;
}

运行结果:

cpp 复制代码
2024-1-1

当执行:

cpp 复制代码
Date d;

对象 d 创建时,构造函数 Date() 会自动调用。


三、构造函数不是创建对象

构造函数名字里有"构造",但他并不是负责开辟空间的。

对象空间由编译器根据类的成员变量自动分配。

构造函数真正负责的是:

cpp 复制代码
初始化对象中的成员变量。

比如:

cpp 复制代码
Date d;

这一步会创建对象空间。

随后构造函数会自动执行,把 _year、_month、_day 设置成初始值。


四、带参数的构造函数

构造函数也可带参数:

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

class Date {
	public:
		Date(int year, int month, int day) {
			_year = year;
			_month = month;
			_day = day;
		}
		
		void Print() {
			cout << _year << "-" << _month << "-" << _day << endl;
		}
	
	private:
		int _year;
		int _month;
		int _day;
};

int main() {
	Date d(2025, 5, 16);
	d.Print(); 
	
	return 0;
}

运行结果:

cpp 复制代码
2025-5-16

这里:

cpp 复制代码
Date d(2025, 5, 16);

创建对象时,会自动调用带三个参数的构造函数。


五、构造函数支持重载

构造函数也可以重载。

因为构造函数的函数名都可以和类名相同,所以能否构成重载主要看参数列表是否支持。

例如:

cpp 复制代码
class Date {
	public:
		Date() {
			_year = 2024;
			_month = 1;
			_day = 1;
		}  
		
		Date(int year, int month, int day) {
			_year = year;
			_month = month;
			_day = day;
		}
		
		void Print() {
			cout << _year << "-" << _month << "-" << _day << endl;
		}
	
	private:
		int _year;
		int _month;
		int _day;
};

使用时:

cpp 复制代码
Date d1;
Date d2(2025, 5, 16);

d1 调用无参构造函数,d2 调用带参构造函数。


六、默认构造函数

默认构造函数时指不需要传参就可以调用的构造函数。

常见的有三种形式:

cpp 复制代码
1. 编译器自己是生成的默认构造函数;
2. 用户自己写的无参构造函数;
3. 用户自己写的全缺省构造函数。

1. 无参构造函数

cpp 复制代码
Date() {
    _year = 2024;
    _month = 1;
    _day = 1;
}

调用:

cpp 复制代码
Date d;

注意,无参构造函数创建对象不要写成:

cpp 复制代码
Date d();

这不是创建对象,而容易被编译器理解成函数声明。


2. 全缺省构造函数

cpp 复制代码
Date(int year = 2024, int month = 1, int day = 1) {
	_year = year;
	_month = month;
	_day = day;
}

这种构造函数既可以不传参,也可以传部分参数或全部传参。

cpp 复制代码
Date d1;
Date d2(2025);
Date d3(2025, 5);
Date d4(2025, 5, 16);

全缺省构造函数比较灵活。


七、无参构造和全缺省构造不能同时存在

下面这种写法会出问题:

cpp 复制代码
class Date {
	public:
		Date() {
			_year = 2024;
			_month = 1;
			_day = 1;
		}  
		
		Date(int year = 2024, int month = 1, int day = 1) {
			_year = year;
			_month = month;
			_day = day;
		}
	
	private:
		int _year;
		int _month;
		int _day;
};

因为当我们写:

cpp 复制代码
Date d;

编译器会发现:

cpp 复制代码
无参构造函数可以调用;
全缺省构造函数也可以不传参调用。

这样就产生了歧义,编译器不知道应该调用哪一个。

所以要记住:

无参构造函数和全缺省构造函数不能同时存在。


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

如果我们没有写任何构造函数,编译器会生成一个默认的构造函数。

例如:

cpp 复制代码
class Date {
    private:
        int _year;
        int _month;
        int _day;
};

这时可以写:

cpp 复制代码
Date d;

但是要注意:

编译器自动生成的默认构造函数,对内置类型成员变量一般不会初始化。

比如 int、char、double 这类内置类型,仍然可能是随机值。


九、自己写了构造函数后,编译器还会生成默认构造函数吗?

如果用户显示写了任意构造函数,编译器就不会子自动生成默认构造函数。

例如:

cpp 复制代码
class Date {
	public:
		Date(int year, int month, int day) {
			_year = year;
			_month = month;
			_day = day;
		}
		
	private:
		int _year;
		int _month;
		int _day;
};

这时如果写:

cpp 复制代码
Date d;

就会报错。

因为你已经写了带参构造函数,编译器不会再自动生成无参默认构造函数。

如果你想创建无参对象,就需要自己再写一个无参构造函数,或者使用全缺省构造函数。


十、小结

本篇主要学习了C++中的构造函数。

需要记住:

  1. 构造函数是特殊的成员函数;
  2. 构造函数名必须和类名相同;
  3. 构造函数没有返回值;
  4. 构造函数在对象创建时自动调用;
  5. 构造函数的主要作用是初始化对象;
  6. 构造函数可以重载;
  7. 默认构造函数是不需要传参就能调用的构造函数;
  8. 无参构造函数和全缺省构造函数不能同时存在;
  9. 如果用户自己写了构造函数,编译器不会再自动生成默认构造函数;
  10. 编译器自动生成的默认构造函数一般不会初始化内置类型成员。

构造函数是类和对象部分的重点内容,后面学习析构函数、拷贝构造函数、运算符重载时都会继续用到。

相关推荐
旖旎夜光1 分钟前
LeetCode 238:除自身以外数组的乘积(前缀和) —— 题解
数据结构·c++·算法·leetcode·前缀和
Escalating_xu12 分钟前
【C++类和对象(上)】从类的定义、封装与对象模型到内存对齐和 this 指针
开发语言·前端·c++
吃着火锅x唱着歌15 分钟前
Effective C++ 学习笔记 条款45 运用成员函数模板接受所有兼容类型
c++·笔记·学习
爱和冰阔落27 分钟前
【Linux】多线程打印为什么会乱?pthread 创建、等待、退出、取消与分离全实战
linux·运维·c++·redis
luj_176830 分钟前
尾椎藏今生记忆?骨盆对应不确定性
开发语言·网络·c++·经验分享·算法
断点之下41 分钟前
C++类和对象:六个默认成员函数详解
开发语言·c++
库玛西3 小时前
深入浅出传输层:UDP 与 TCP 协议全景指南
linux·服务器·网络·c++·笔记·tcp/ip·udp
Chester_19999 小时前
CSP202203C.计算资源调度器
开发语言·数据结构·c++·蓝桥杯
会周易的程序员10 小时前
给 PLC 写一个字节码虚拟机:STVM 虚拟机架构设计
开发语言·c++·虚拟机·软plc·iec61131·stvm
小灰灰搞电子11 小时前
完全驾驭 Qt 与数据库:C++ ORM 框架 QxOrm 原理与实践指南
数据库·c++·qt