构造函数
构造函数,是一个比较特殊的函数。我们在使用一个类的对象的时候,需要为其分配空间。空间分配完成之后,我们一般都会对创建的对象的属性进行初始化的操作。而这个过程就可以在构造函数中来完成了。
因此:构造函数是一个函数
- 触发时机:在对象创建的时候触发
- 作用:对对象的属性进行初始化的赋值操作
1.构造函数定义
- 构造函数的名字,必须和类的名字相同
- 构造函数不能写返回值类型!
- 构造函数可以有不同的重载!
- 构造函数需要公开权限 public
c++
#include<iostream>
using namespace std;
class Person {
public:
Person() {
cout << "我在创建对象时被调用,并且没有参数" << endl;
}
// 重载
Person(int age) {
cout << "我在创建对象时被调用,参数为"<< age << endl;
}
};注意
- 如果我们没有在一个类中写任何的构造函数,系统会为其添加一个
public权限的无参构造函数,可以让我们创建对象 - 如果我们给一个类写构造函数了,此时系统将不再提供任何默认的构造函数。
2.构造函数调用
2.1 显式调用
通过类名 对象名 = 构造函数(参数)语法去声明并调用类的构造函数
c++
#include<iostream>
using namespace std;
class Person {
public:
Person() {
cout << "我在创建对象时被调用,并且没有参数" << endl;
}
// 重载
Person(int age) {
cout << "我在创建对象时被调用,参数为"<< age << endl;
}
};
int main() {
Person p1 = Person();
Person p2 = Person(18);
return 0;
}以上调用方法可以使用以下缩写
c++
Person p1;
Person p2(18);
注意
通过缩写的方式,若调用无参的构造函数去创建对象,不能写小括号()
若写了小括号,则会被认为声明了一个返回类型为类名(Person)的函数
c++
Person p2();2.2 隐式调用
隐式调用可以不写构造函数的名字,直接把参数写在一堆大括号{}中
- 此时系统会根据大括号中的实参的数量和类型,找到与之匹配的构造函数调用
- 若只有一个参数,可以省略大括号
c++
#include<iostream>
using namespace std;
class Person {
public:
Person() {
cout << "我在创建对象时被调用,并且没有参数" << endl;
}
// 重载
Person(int age) {
cout << "我在创建对象时被调用,参数为"<< age << endl;
}
Person(int age,string name) {
cout << "我在创建对象时被调用,参数为"<< age <<"名字为"<< name << endl;
}
};
int main() {
Person p1 = {};
Person p2 = 18;
Person p3 = {18,"xiazhi"};
return 0;
}3.explicit
explicit是用来修饰构造函数的,写在构造函数之前。表示无法通过隐式调用来访问这个构造函数
c++
#include<iostream>
using namespace std;
class Person {
public:
Person() {
cout << "我在创建对象时被调用,并且没有参数" << endl;
}
// 重载
explicit Person(int age) {
cout << "我在创建对象时被调用,参数为"<< age << endl;
}
Person(int age,string name) {
cout << "我在创建对象时被调用,参数为"<< age <<"名字为"<< name << endl;
}
};
int main() {
Person p1 = {};
Person p2 = 18;
Person p3 = {18,"xiazhi"};
return 0;
}
4.初始化列表
构造函数的初衷就是用来对对象的属性进行初始化的赋值操作
我们可以在创建对象时,给某些数据一些指定的值,这个值可以是我们通过构造函数参数传入,也可以写一个字面量的值
c++
#include<iostream>
using namespace std;
class Person {
public:
string name;
int age;
string sex;
double tall;
string hobby;
string health;
Person(string n,int a,string s,double t,string h) {
name = n;
age = a;
sex = s;
tall = t;
hobby = h;
health = "健康";
}
};
int main() {
Person p1("xiazhi",18,"男",181.00,"唱,跳,rap,篮球");
return 0;
}TIP
在成员函数中需要访问成员变量,可以直接写变量名,这样就出现一个问题,构造函数的名称和成员变量的名称不能写成一样。鉴于此,后面会学习到this的知识
如果构造函数的参数过多,我们需要一行一行的给成员属性赋值,为了方便,c++提供了构造函数的初始化列表
- 在构造函数形参括号的后面写一个
:,后面通过成员变量名(值)的方式直接给成员变量赋值,多个变量使用逗号,隔开
c++
#include<iostream>
using namespace std;
class Person {
public:
string name;
int age;
string sex;
double tall;
string hobby;
string health;
Person(string n, int a, string s, double t, string h) :name(n), age(a), sex(s), tall(t), hobby(h), health("健康") {
// ...
}
};
int main() {
Person p1("xiazhi", 18, "男", 181.00, "唱,跳,rap,篮球");
cout << p1.name << endl; // xiazhi
cout << p1.age << endl; // 18
cout << p1.sex << endl; // 男
cout << p1.tall << endl; // 181.00
cout << p1.hobby << endl; // 唱,跳,rap,篮球
cout << p1.health << endl; // 健康
return 0;
}通过构造函数的初始化列表,也可以将构造函数的形参名称写成和成员变量一样
c++
#include<iostream>
using namespace std;
class Person {
public:
string name;
int age;
Person(string name, int age) :name(name), age(age) {
// ...
}
};
int main() {
Person p1("xiazhi", 18);
cout << p1.name << endl; // xiazhi
cout << p1.age << endl; // 18
return 0;
}5.拷贝构造函数
5.1 语法
当已经创建一个对象时,可以直接把这个对象赋值给另一个对象,这样就完成了构造函数的拷贝,并且两个对象中的数据处于不同地址,不会冲突
c++
#include<iostream>
using namespace std;
class Person {
public:
string name;
int age;
Person(string name, int age) :name(name), age(age) {
// ...
}
};
int main() {
Person p1("xiazhi", 18);
Person p2 = p1;
cout << p1.name << endl;
cout << p2.name << endl;
cout << &p1.name << endl;
cout << &p2.name << endl;
return 0;
}
5.2 手写拷贝
c++
class Person {
public:
string name;
int age;
Person(string name, int age) :name(name), age(age) {
// ...
}
Person(const Person& p) :name(p.name), age(p.age) {
cout << "拷贝构造函数被调用了" << endl;
// 拷贝构造的其他逻辑...
}
};
int main() {
Person p1("xiazhi", 18);
Person p2(p1);
cout << p1.name << endl;
cout << p2.name << endl;
cout << &p1.name << endl;
cout << &p2.name << endl;
return 0;
}
6.匿名对象
匿名对象(也称临时对象)
- 临时对象:匿名对象通常是临时创建的,用于某个特定的操作或任务,不需要在程序中保留其状态或引用。
- 作为函数参数:匿名对象可以作为函数的参数传递,这样可以简化代码,避免创建额外的对象。
- 作为函数返回值:函数可以返回匿名对象,这样可以在调用函数时直接得到临时对象的值。
- 生命周期:匿名对象的生命周期通常很短,只在当前表达式或语句中有效(当前行)。一旦表达式或语句结束,匿名对象就会被销毁。因此,在使用匿名对象时要注意其生命周期,避免出现悬空指针或未定义行为。
6.1 创建匿名对象
产生匿名对象的三种情况
- 以值的方式给函数传参;
Cat():生成了一个匿名对象,执行完Cat( )代码后,此匿名对象就此消失。这就是匿名对象的生命周期。Cat cc = Cat():首先生成了一个匿名对象,然后将此匿名对象变为了cc对象,其生命周期就变成了cc对象的生命周期。
- 类型转换
- 函数需要返回一个对象时;
return temp;
