在完成对C语言的学习后,我最近开始了对C++和Java的学习,目前跟着视频学习了一些语法,也跟着敲了一些代码,有了一定的掌握程度。现在将跟着视频做的笔记进行整理。本篇博客是整理C++知识点的第十二篇博客。
本篇博客介绍了C++的构造函数。
本系列博客所有C++代码都在Visual Studio 2022环境下编译运行。程序为64位。
目录
构造函数
这一部分接着上一篇对构造函数的初步介绍。
拷贝构造函数的调用时机
C++中,调用拷贝构造函数的时机通常有这三种情况:
使用一个已经创建的对象初始化一个新对象。
用值传递给函数参数传参。
以值的方式返回局部对象。
#include<iostream>
using namespace std;
class test {
public:
int age;
test() {
cout << "This is A" << endl;
}
test(const int num) {
age = num;
cout << "This is B" << endl;
cout << "Age = " << age << endl;
}
test(const test& temp) {
age = temp.age;
cout << "This is C" << endl;
cout << "Age = " << age << endl;
}
};
int main(void)
{
test test1;
test test2(10);
test test3(test2);
return 0;
}
程序中用已经创建的test2初始化一个新的对象test3。
程序的输出是:
This is A
This is B
Age = 10
This is C
Age = 10
#include<iostream>
using namespace std;
class test {
public:
int age;
test() {
cout << "This is A" << endl;
}
test(const int num) {
age = num;
cout << "This is B" << endl;
cout << "Age = " << age << endl;
}
test(const test& temp) {
age = temp.age;
cout << "This is C" << endl;
cout << "Age = " << age << endl;
}
};
void testfunc(test temp);
int main(void)
{
test test1(10);
testfunc(test1);
return 0;
}
void testfunc(test temp)
{
return;
}
程序创建了一个test1对象,随后将这个对象作为参数以值传递的方式传递给testfunc函数。testfunc函数只接受这个参数,什么也不执行。因为值传递需要拷贝,所以会执行拷贝构造函数。
程序的输出是:
This is B
Age = 10
This is C
Age = 10
#include<iostream>
using namespace std;
class test {
public:
int age;
test() {
cout << "This is A" << endl;
}
test(const int num) {
age = num;
cout << "This is B" << endl;
cout << "Age = " << age << endl;
}
test(const test& temp) {
age = temp.age;
cout << "This is C" << endl;
cout << "Age = " << age << endl;
}
};
test testfunc(void);
int main(void)
{
test test2 = testfunc();
return 0;
}
test testfunc(void)
{
test test1(10);
return test1;
}
程序进入main函数后,先执行testfunc函数,testfunc函数创建了一个对象,并将该对象返回main函数,main函数接收后返回。由于返回值也是拷贝,会调用拷贝构造函数。
程序的输出是:
This is B
Age = 10
This is C
Age = 10
构造函数调用规则
默认情况下,C++编译器会给一个类添加一个默认构造函数,此构造函数无参,函数体为空。还会添加一个默认析构函数,函数体为空。还会添加一个默认拷贝构造函数,对属性进行值拷贝。
如果已经自定义有参构造函数,那么编译器不再提供默认无参构造函数,但是会提供默认拷贝构造。如果自定义拷贝构造函数,那么编译器不会提供其他构造函数。
深拷贝与浅拷贝
浅拷贝就是简单的赋值拷贝操作,深拷贝会在堆区重新申请空间,进行拷贝。
编译器默认浅拷贝,这样在释放空间时造成重复释放,会导致程序崩溃。如果一个类中有堆区的数据,并且涉及到拷贝,要自己提供拷贝构造函数进行深拷贝。
#include<iostream>
using namespace std;
class test {
public:
int age;
int* height;
test() {
cout << "This is A" << endl;
}
test(const int numage, const int numheight) {
age = numage;
height = new int(numheight);
cout << "This is B" << endl;
cout << "Age = " << age << endl;
cout << "Height = " << *height << endl;
}
test(const test& temp) {
age = temp.age;
height = new int(*temp.height);
cout << "This is C" << endl;
cout << "Age = " << age << endl;
cout << "Height = " << *height << endl;
}
~test() {
delete height;
cout << "This is D" << endl;
}
};
int main(void)
{
test test1(20, 170);
test test2(test1);
return 0;
}
test类提供只输出This is A的无参构造函数。同时提供一个有参构造函数,对age和height进行赋值,age存储在栈区,height存储在堆区,进行了内存开辟。同时输出This is B和成员变量信息。同时提供拷贝构造函数,对height进行了深拷贝,同时输出This is C和成员变量信息。test类的析构函数将height销毁,同时输出This is D。
main函数用有参构造函数和拷贝构造函数进行初始化。程序的输出是:
This is B
Age = 20
Height = 170
This is C
Age = 20
Height = 170
This is D
This is D
初始化列表
C++提供了初始化列表,用来初始化属性。语法是:
构造函数():属性1(值1),属性2(值2),属性3(值3)...{...}
#include<iostream>
using namespace std;
class test {
public:
int A;
int B;
int C;
test() :A(10), B(15), C(20){}
test(int a,int b,int c) :A(10), B(15), C(20)
{
A = a;
B = b;
C = c;
}
void show() {
cout << "A = " << A << endl;
cout << "B = " << B << endl;
cout << "C = " << C << endl;
}
};
int main(void)
{
test atest;
atest.show();
return 0;
}
程序创建了test类,test类有成员A,B,C,构造函数中默认初始化值为10,15,20。程序创建了一个类对象,并调用了无参构造函数。程序的输出是:
A = 10
B = 15
C = 20
如果用构造函数,传入三个0作为参数,程序的输出是:
A = 0
B = 0
C = 0
类对象作为类成员
一个类的成员可以是另一个类的一个对象。
当有其他类的对象作为本类成员时,构造时先构造类对象,后构造自身,析构时相反。
#include<iostream>
#include<string>
using namespace std;
class Phone {
public:
string brand;
Phone(void) {
cout << "A" << endl;
}
~Phone(void) {
cout << "Z" << endl;
}
};
class Person {
public:
string name;
Phone phone;
Person(string tempname, string tempbrand){
cout << "a" << endl;
name = tempname;
phone.brand = tempbrand;
}
void show() {
cout << "The name is " << name << endl;
cout << "The phone is " << phone.brand << endl;
}
~Person() {
cout << "z" << endl;
}
};
int main(void)
{
Person people("Allen", "Apple");
people.show();
return 0;
}
程序提供了Phone类,有一个成员变量brand,构造函数输出A,析构函数输出Z。程序还有Person类,有一个成员变量是字符串name,另一个成员变量是Phone类对象phone。Person类的带参构造函数输出a,同时对成员变量进行赋值。析构函数输出z,show函数输出成员变量信息。main函数中实例化Person类对象并执行此对象的show函数。
程序的输出是:
A
a
The name is Allen
The phone is Apple
z
Z