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. 编译器自动生成的默认构造函数一般不会初始化内置类型成员。

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

相关推荐
basketball6166 小时前
C++ 嵌套类完全指南:类中类的巧妙设计
开发语言·c++
kyle~7 小时前
ros_gz_bridge---底层通信的实现
c++·机器人·仿真·ros2
Jasmine_llq7 小时前
《B4261 [GESP202503 三级] 2025》
开发语言·c++·算法·条件判断算法·位运算恒等式推导·简单算术运算
小张成长计划..7 小时前
【C++】32:智能指针
c++
咩咦7 小时前
C++学习笔记19:运算符重载基础与赋值运算符重载
c++·学习笔记·类和对象·运算符重载·赋值运算符·operator
无限进步_8 小时前
C++异常机制:抛出、捕获与栈展开
开发语言·c++·安全
王老师青少年编程8 小时前
csp信奥赛C++高频考点专项训练之前缀和&差分 --【一维前缀和】:宝石串
c++·前缀和·csp·高频考点·信奥赛·宝石串
梓䈑8 小时前
【算法题攻略】模拟
c++·算法
vKd0Ff21L8 小时前
如何在Dev-C++中设置TDM-GCC为默认编译器第九十一篇
java·jvm·c++