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

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

相关推荐
·薯条大王8 小时前
经济实惠玩云服务器|一台云服务器多人共用,子账号配置教程
java·linux·运维·服务器·汇编·c++·python
hansang_IR13 小时前
【题解】LC:倍增 / 区间并查集(Range Parallel Unionfind)
c++·算法·并查集
东东最爱敲键盘13 小时前
day7.c++继承
c++
沫璃染墨14 小时前
《从零入门Linux系统篇(十五):系统工具篇·六——GDB调试器详解:从程序执行控制到高级调试技巧》
linux·运维·服务器·c语言·c++
吃着火锅x唱着歌14 小时前
Effective C++ 学习笔记 条款40 明智而审慎地使用多重继承
c++·笔记·学习
醉城夜风~14 小时前
(超详细)C++ STL list容器详解:从使用方法到双向链表底层原理全面解析
c++·windows
烟花落o15 小时前
C++ 从 C 到进阶 ②:引用、inline 、nullptr
c++·引用·inline·nullptr·c++入门
liulilittle15 小时前
MOE路由:路由(logits: top-k/8)
c++·人工智能·算法·机器学习·llm
旖旎夜光15 小时前
LeetCode 11:盛最多水的容器(双指针问题) —— 题解
数据结构·c++·算法·leetcode·双指针
我不会插花弄玉18 小时前
15.map,set下:AVL树,红黑树和map,set的封装【由浅入深-C++】
c++·stl