c++中的构造函数
C++中的构造函数可以分为一下几种:
- 默认构造函数
- 初始化构造函数(有参数)
- 拷贝构造函数
- 移动构造函数(move和右值引用)
- 委托构造函数
- 转换构造函数
#include <iostream> using namespace std; class Student{ public: Student(){//默认构造函数,没有参数 this->age = 20; this->num = 1000; }; Student(int a, int n):age(a), num(n){}; //初始化构造函数,有参数和参数列表 Student(const Student& s){//拷贝构造函数,这里与编译器生成的一致 this->age = s.age; this->num = s.num; }; Student(int r){ //转换构造函数,形参是其他类型变量,且只有一个形参 this->age = r; this->num = 1002; }; ~Student(){} public: int age; int num; };
int main(){ Student s1; Student s2(18,1001); int a = 10; Student s3(a); Student s4(s3); printf("s1 age:%d, num:%d\n", s1.age, s1.num); printf("s2 age:%d, num:%d\n", s2.age, s2.num); printf("s3 age:%d, num:%d\n", s3.age, s3.num); printf("s2 age:%d, num:%d\n", s4.age, s4.num); return 0; } //运行结果 //s1 age:20, num:1000 //s2 age:18, num:1001 //s3 age:10, num:1002 //s2 age:10, num:1002
-
class Person { public: Person() :Person(1, 'a') {} //委托构造函数 Person(int i) : Person(i, 'a') {} //委托构造函数 Person(char ch) : Person(1, ch) {} //委托构造函数 private: Person(int i, char ch) :type(i), name(ch) {/*其他初始化信息*/} int type{ 1 }; char name{ 'a' }; };
- 默认构造函数和初始化构造函数在定义类的对象,完成对象的初始化工作
- 复制构造函数用于复制本类的对象
- 转换构造函数用于将其他类型的变量,隐式转换为本类对象
class A { public: int a; A(int i) :a(i) { std::cout << "a" << i << " 构造" << std::endl; } ~A() { std::cout << "a" << a << " 析构" << std::endl; } A(const A& another) { a = another.a; std::cout << "A 拷贝" << another.a << std::endl; } /*A(const A&& another) { a = another.a; std::cout << "A 移动" << another.a << std::endl; }*/ A& operator=(const A& another) { a = another.a; std::cout << "A =" << another.a << std::endl; return *this; } }; A func(int k) { std::cout << "func" << std::endl; A res(k); return res; } int main() { std::cout << "a1" << std::endl; A a1 = A(1); std::cout << "a2" << std::endl; A a2(2); a2 = func(-2); std::cout << "a3" << std::endl; A a3 = func(-3); return 0; }
//vs2022运行结构
即用=初始化也属于拷贝构造函数。
此处需注意func函数被返回值优化,所以在函数内部仅存在一次构造和一次析构函数,若去掉优化则会变为一次构造,一次拷贝,两次析构,这是因为没有优化的时候,需要自己去创建一个临时对象,再将其拷贝到返回值上,而通过优化可以减少这些开销。
关于类成员初始化
一般对类成员初始化有两种方式,一种是使用初始化列表,一种是在构造函数内直接赋值。推荐使用初始化列表。
在函数内赋值初始化是在类成员已经申请完空间后执行的,也就是说当进入构造函数时,所有类成员均已被分配内存空间。因此此时再对类成员赋值相当于执行运算符=。
而使用初始化列表,是直接对类成员进行拷贝初始化,避免了初始化完之后再调用运算符=这一过程。
需注意以下情况必须使用初始化列表进行初始化:
① 当初始化一个引用成员时;
② 当初始化一个常量成员时;
③ 当调用一个基类的构造函数,而它拥有一组参数时;
④ 当调用一个成员类的构造函数,而它拥有一组参数时;
c++11支持对数据成员提供一个初始值,即在声明成员时可以直接使用=给其一个初始值。但是需注意不能使用圆括号()提供初始值,是因为使用()提供初始值则会使其和函数声明形式一致。
class A { public: int x=1; //合法 B z(1); //该形式无法区分其到底是成员函数还是成员变量 };
参考文章:https://interviewguide.cn/notes/03-hunting_job/02-interview/01-01-02-basic.html