C++中的构造函数大全(总结)
文章目录
构造函数的基本格式
声明
只需要记住一点,构造函数名=类名
class MyClass {
public:
MyClass() { }
};
类外定义
类名 : : 类名 ( ) { } 类名::类名()\{ \} 类名::类名(){}
MyClass::MyClass() { }
初始化成员变量的构造函数
类名 ( 参数列表 ) : 成员变量名 ( 用于初始化的参数 ) , 成员变量名 ( 用于初始化的参数 ) { } 类名(参数列表):成员变量名(用于初始化的参数),成员变量名(用于初始化的参数)\{ \} 类名(参数列表):成员变量名(用于初始化的参数),成员变量名(用于初始化的参数){}
class Student {
private:
string name;
int age;
double score;
public:
Student(const string& n, int a, double s) : name(n), age(a), score(s) {}
};
注意:成员的初始化顺序只取决于它们在类中声明的顺序,与在初始化列表中的书写顺序无关。
初始化成员对象的构造函数
类名 ( 参数列表 ) : 成员对象名 ( 用于初始化的参数 ) , 成员变量名 ( 用于初始化的参数 ) { } 类名(参数列表):成员对象名(用于初始化的参数),成员变量名(用于初始化的参数)\{ \} 类名(参数列表):成员对象名(用于初始化的参数),成员变量名(用于初始化的参数){}
class Parent {
private:
string fatherName;
string motherName;
string phone;
public:
// Parent 类的带参构造函数
Parent(const string& father, const string& mother, const string& ph)
: fatherName(father), motherName(mother), phone(ph) {
cout << "Parent 带参构造函数: " << father << ", " << mother << endl;
}
};
class Student {
private:
string name;
int age;
double score;
Parent parents; // 成员对象 - Parent类的实例
public:
// 显式初始化 Parent 成员对象
Student(const string& n, int a, double s, const string& father, const string& mother, const string& phone)
: name(n), age(a), score(s), parents(father, mother, phone) {
cout << "Student 构造函数(传递信息)" << endl;
}
// 直接传递 Parent 对象---使用复制构造函数
Student(const string& n, int a, double s, const Parent& p)
: name(n), age(a), score(s), parents(p) {
cout << "Student 构造函数(传递Parent对象)" << endl;
}
};
调用基类构造函数的派生类构造函数
派生类名 ( 参数列表 ) : 基类名 ( 参数列表 ) , 成员对象名 ( 用于初始化的参数 ) , 成员变量名 ( 用于初始化的参数 ) { } 派生类名(参数列表):基类名(参数列表),成员对象名(用于初始化的参数),成员变量名(用于初始化的参数)\{ \} 派生类名(参数列表):基类名(参数列表),成员对象名(用于初始化的参数),成员变量名(用于初始化的参数){}
class Person {
private:
string name;
int age;
public:
// 构造函数
Person(const string& n, int a) : name(n), age(a) { }
};
class Student : public Person { // public继承
private:
double score;
string studentId;
public:
// 构造函数
Student(const string& n, int a, double s, const string& sid)
: Person(n, a, id_num), score(s), studentId(sid) {
}
};
函数重载情况下的构造函数
根据函数重载的性质,同名的函数可以根据参数的不同种类从而调用不同的函数,构造函数也是如此,可以有多个构造函数。
class Student {//函数重载
private:
string name;
int age;
double score;
public:
// 多个构造函数 - 参数列表不同
Student() : name("未知"), age(0), score(0) {} // 无参
Student(const string& n) : name(n), age(0), score(0) {} // 一个参数
Student(const string& n, int a) : name(n), age(a), score(0) {} // 两个参数
Student(const string& n, int a, double s) : name(n), age(a), score(s) {} // 三个参数
};
默认构造函数(只能有一个)
默认构造函数:可以不带任何参数调用的构造函数。分为以下三种情况。
调用时机:没有传参
1、编译器生成的默认构造函数
在代码当中没有写明构造函数
//无
2、显式无参默认构造函数
class MyClass {
public:
MyClass() { } // 显式无参默认构造函数
};
3、所有参数都有默认值的默认构造函数
class MyClass {
public:
MyClass(int x = 0, double y = 0.0) { }
};
只能有一个
根据函数重载的性质,同名的函数可以根据参数的不同种类从而调用不同的函数,构造函数也是如此,可以有多个构造函数。**但是,默认构造函数只能有一个。**也就是说,2可以出现,3也可以出现,但是2和3同时出现就会报错。
class MyClass {
public:
MyClass() { } // 默认构造函数
MyClass(int x = 0) { } // 这也是默认构造函数!冲突!
};
复制/拷贝构造函数
复制构造函数:用一个已存在的对象来初始化一个新对象(拷贝一个副本)
如果没有显示定义则会生成默认的复制构造函数
调用时机:用已有对象初始化新对象(传入同类对象)、将对象作为函数参数传递、函数返回值是一个对象
类名 ( c o n s t 类名 & 对象名 ) 类名(const \ \ 类名\& \ \ 对象名) 类名(const 类名& 对象名)
括号里的是指向类对象的常量引用
class MyClass {
public:
// 复制构造函数
MyClass(const MyClass& other) {
}
};
移动构造函数(Move Constructor)
移动语义
Q:什么是移动语义?
A:实际文件还留在原来位置,而只是修改记录。
Q:在什么情况下触发移动语义?
A:在大量数据需要进行拷贝的情况下,并且还需要删除临时的存储对象
类似于“夺舍”
右值引用
右值
在讲右值引用之前我们先来介绍一下什么是右值
重点关注红线
举例:
int getNumber() {
return 100; // 返回值是右值
}
string getName() {
return "Alice"; // 返回值是右值
}
int main() {
// 左值例子
int x = 5; // x是左值
int y = x; // x是左值(但这里被当作右值使用)
string name = "Bob"; // name是左值
int arr[5] = {0}; // arr是左值
// 右值例子
int z = 10; // 10是右值
string s = "Hello"; // "Hello"是右值
int sum = x + y; // (x+y)的结果是右值
int num = getNumber(); // getNumber()返回值是右值
// 验证左值可以取地址
cout << "x的地址: " << &x << endl;
cout << "name的地址: " << &name << endl;
cout << "arr的地址: " << &arr << endl;
// 右值不能取地址(下面的代码会编译错误)
// &10; // 错误
// &"Hello"; // 错误
// &(x + y); // 错误
// &getNumber(); // 错误
return 0;
}
右值引用
右值引用的格式为
类型名 & & 右值引用变量名 = 右值表达式 类型名\&\& \ \ \ 右值引用变量名 = 右值表达式 类型名&& 右值引用变量名=右值表达式
举例:
int&& rref = 5 + 3;
注意:这里的右值引用变量名是个左值
另外右值引用的定义主要是为了区分左值引用
对于左值引用其格式为
类型名 & & 左值引用变量名 = 左值变量 类型名\&\& \ \ \ 左值引用变量名 = 左值变量 类型名&& 左值引用变量名=左值变量
左值引用也就是俗称的引用,其本质是给变量取别名,所以左值变量得是一个变量,而不能是表达式。(具体区分见表格)
移动构造函数
调用时机:使用左值初始化对象时使用复制构造函数,使用右值初始化对象时使用移动构造函数
格式:
类名 : : 类名 ( 类名 & & 对象名 ) 类名::类名(类名\&\& \ \ 对象名) 类名::类名(类名&& 对象名)
委托构造函数
允许一个构造函数调用同一个类中的另一个构造函数,从而避免代码重复。
class 类名 { public: // 主构造函数 类名(参数列表1) : 初始化列表 {} // 委托构造函数 类名(参数列表2) : 类名(构造函数参数-需参考参数列表1) {} 类名(参数列表3) : 类名(构造函数参数-需参考参数列表1) {} }; \begin{aligned} &\text{class 类名 \{} \\ &\quad \text{public:} \\ &\quad \quad \text{// 主构造函数} \\ &\quad \quad \text{类名(参数列表1) : 初始化列表 \{\}} \\ &\quad \quad \text{// 委托构造函数} \\ &\quad \quad \text{类名(参数列表2) : 类名(构造函数参数-需参考参数列表1) \{\}} \\ &\quad \quad \text{类名(参数列表3) : 类名(构造函数参数-需参考参数列表1) \{\}} \\ &\text{\};} \\ \end{aligned} class 类名 {public:// 主构造函数类名(参数列表1) : 初始化列表 {}// 委托构造函数类名(参数列表2) : 类名(构造函数参数-需参考参数列表1) {}类名(参数列表3) : 类名(构造函数参数-需参考参数列表1) {}};
注意:所有委托构造函数完成初始化之后,先执行主构造函数的函数体,再执行自身的函数体。
#include <iostream>
#include <vector>
using namespace std;
class Rectangle {
private:
double width;
double height;
string color;
vector<string> tags;
public:
// 主构造函数 - 完成所有初始化
Rectangle(double w, double h, const string& c, const vector<string>& t)
: width(w), height(h), color(c), tags(t) {
cout << "创建矩形: " << w << "x" << h << endl;
}
// 委托构造函数 - 提供默认颜色和空标签
Rectangle(double w, double h)
: Rectangle(w, h, "黑色", {}) {
cout << "使用默认颜色" << endl;
}
// 委托构造函数 - 创建正方形
Rectangle(double side)
: Rectangle(side, side, "蓝色", {"正方形"}) {
cout << "创建正方形" << endl;
}
// 委托构造函数 - 默认矩形
Rectangle() : Rectangle(1.0, 1.0) {
cout << "创建默认矩形" << endl;
}
};
继承构造函数
class 派生类 : 访问说明符 基类 { public: using 基类::基类; // 继承基类的所有构造函数 }; \begin{aligned} &\text{class 派生类 : 访问说明符 基类 \{} \\ &\quad \text{public:} \\ &\quad \quad \text{using 基类::基类; // 继承基类的所有构造函数} \\ &\text{\};} \\ \end{aligned} class 派生类 : 访问说明符 基类 {public:using 基类::基类; // 继承基类的所有构造函数};
转换构造函数(Converting Constructor)
只有一个参数的构造函数统称为转换构造函数
关键字default、delete、explicit
default
显式要求编译器生成默认的特殊成员函数
class MyClass {
public:
int value;
// 显式要求编译器生成默认构造函数
MyClass() = default;
// 显式要求编译器生成默认析构函数
~MyClass() = default;
// 显式要求编译器生成默认拷贝构造函数
MyClass(const MyClass&) = default;
// 显式要求编译器生成默认移动构造函数
MyClass(MyClass&&) = default;
};
delete
显式删除特殊成员函数,禁止某些操作
class NonCopyable {
public:
int value;
NonCopyable(int v) : value(v) {}
// 删除拷贝构造函数 - 禁止拷贝
NonCopyable(const NonCopyable&) = delete;
};
explicit
防止构造函数的隐式类型转换。
class MyClass {
public:
// 未使用 explicit - 允许隐式转换
// MyClass(int x) { }
// 使用 explicit - 禁止隐式转换
explicit MyClass(double y) { }
};
更多推荐



所有评论(0)