C++学习记录-构造函数和析构函数

某些函数在调用时不需要显式提供函数名,编译器会自动调用,例如类构造函数与类析构函数。

构造函数:

与类同名的成员函数。创建类的一个实例时,编译器自动调用合适的构造函数。

一个类至少有一个构造函数,即可以对构造函数进行重载;每个构造函数的函数签名不同。例:

#include<iostream>
using namespace std;

class Person {
public:
	//没有参数的默认构造函数
	Person();
	//参数类型为const string引用的带参构造函数
	Person(const string& n);
	//参数类型为C风格字符串:const char*的带参构造函数
	Person(const char* n);

	void setName(const string& n);
	void setName(const char* n);
	const string& getName()const;

private:
	string name;

};

构造函数的使用:

int main() {
	//默认构造函数
	Person per;
	//带参构造函数
	Person IvS("Ivan Sutherland");
}

顾名思义,构造函数用于"构造",对数据成员进行初始化,并且负责其他一些对象创建时需要的事务

数据成员的初始化顺序取决于它们在类中被声明的顺序,而与它们在成员初始化列表中出现的顺序无关

构造函数最大的特点:

1.函数名与类名相同

2.没有返回类型

构造函数与其它函数相同,可以进行赋值、判断、循环、调用等功能;可以在类内/类外定义;

对象数组与默认构造函数:

假设C是一个类,可以定义任意维数的C对象数组;若C拥有默认构造函数,数组中每个C对象都会调用默认构造函数。例如:

#pragma once
#include<iostream>
using namespace std;
unsigned n = 0;

class C {
public:
	C() { cout << "C" << ++n << "\n"; }
};

C arr[10];

测试:

#include<iostream>
#include"ctest.h"
using namespace std;

int main(){
	C();
};


输出结果:

构造函数约束对象的创建:

程序员将部分构造函数设计为私有,另一部分设计为公有;私有构造函数不能在类外调用,由类范围属性。

关于构造函数的自动生成:

编译器找不到任何构造函数时,会生成一个公有默认构造函数;

若一个类已声明构造函数,则不会生成公有默认构造函数;

一个类声明了一个非公有的默认构造函数,编译器不生成公有默认构造函数。

在带参构造函数中有两类比较重要:

拷贝构造函数:创建一个新的对象,此对象是另外一个对象的拷贝品;

转型构造函数:用于类型间的转换,只有一个参数,但是第一个之后的每个参数都必须有默认值;

拷贝构造函数:

拷贝构造函数的原型(必须是引用)

//正确:
	Person(const Person&);
	Person(Person&);
//以下错误:
//Person (Person);
//会提示:"'类Person'的复制构造函数不能带有'Pesron'类型的参数"
//多参数:
Person( const Person &p,bool married = false);

若类设计者不提供拷贝构造函数,编译器将自动生成。完成的操作:

将源对象所有数据成员的值逐一赋值给目标对象相应的数据成员

一个类包含指向动态存储空间指针类型的数据成员,就为这个类设计拷贝构造函数

例:

#pragma once
#include<iostream>
using namespace std;

class nameList {

public:
	
	nameList() { size = 0; p = 0; }
	nameList(const string[], int);
	void set(const string&, int);
	void set(const char*, int);

private:
	int size;
	string* p;
};

nameList::nameList(const string s[], int si) {
	size = si;
	p = new string[size];
	for (int i = 0; i < size; i++) {
		p[i] = s[i];
	}
}
#include<iostream>
#include"ctest.h"
using namespace std;

int main() {
	string list[] = { "A","B","C" };
	nameList d1(list, 3);
	
	d1.dump();
	//A,B,C
	nameList d2(d1);
	d2.dump();
	//A,B,C
	d2.set("D", 1);
	d2.dump();
	//A,D,C
	d1.dump();
	//A,D,C

	return 0;

}

上例没有为类nameList定义拷贝构造函数,则定义d2时将会调用编译器提供的拷贝构造函数,将d1的数据成员拷贝到d2;此时指针d1.p和d2.p指向同一块储存空间:数组的第一项的地址。

可能引发危险:操作一个可能会改变另一个的内容

为避免错误,为nameList类提供一个满足要求的拷贝构造函数。

禁止对象拷贝:有些对象较大,进行对象的拷贝操作(例如采用传值方式将对象传递给一个函数或者返回一个对象时),浪费资源。此时通过将拷贝构造函数设计成私有成员来禁止对象间的拷贝操作

关于对象拷贝:

转型构造函数:

一个单参数的构造函数;将一个对象从一种数据类型(由参数指出)转换为另一种数据类型(该构造函数所属的类)

假设函数f的参数类型为Person对象,以一个string作为参数来调用f;

//f的参数类型为Person对象
void f(Person p);

//以一个string类型作为参数来调用f
	string s = "STRING";
	f(s);

需要Person类拥有一个将string转型成Person的转型构造函数,编译器就可以在string对象s上调用这个转型构造函数,构造一个Person对象做f的参数

转型构造函数与隐式类型转换:

例中的Person类的转型构造函数支持隐式类型转换。

隐式类型转换方便但是可能有细微的问题;可以用关键字explicit关闭系统的隐式类型转换功能。

#include<iostream>
using namespace std;

class Person {
public:
//标记为explicit 
	explicit Person(const string& n) { name = n; }
//函数f的形参类型:Person
	void f(Person s);
private:
	string name;
};

int main() {
	
    Person p("per1");
	f(p);
//OK; p is a Person
//使用转型构造函数

	string  b = "per2";
	f(b); 
//ERROR; b is a string
//explicit关键字关闭隐式类型转换

}

构造函数的初始化:

对const类型的数据成员不能直接赋值,需要为构造函数添加一个初始化列表

class C {
public:
	C() :c(0){x = -1;}
private:
		const int c;
     	int x;
};

构造函数初始化程序:

初始化段:冒号+要进行初始化的数据成员+初始值

C() :c(0){x = -1;}

初始化列表的有效范围:

构造函数中,构造函数可以初始化const或者非const数据成员;const数据成员只能用初始化列表初始化。

class C {
public:
	C() :c(0),x(-1){}
private:
		const int c;
     	int x;
};

构造函数与操作符new和new[]:

使用动态方式为一个对象分配存储空间,C++操作符new和new[]飞陪存储空间并且调用相应的构造函数。

析构函数:

类比于对象的创建,在摧毁对象时,会自动调用一个析构函数。(对象的摧毁:以某个类作为数据类型的变量超出其作用范围;用delete操作符删除动态分配的对象)

特点:

1.是一个成员函数

2.(类C) 析构函数的原型:~C();

3.析构函数不带参数,不能被重载,所以每个类只有一个析构函数

4.析构函数没有返回类型

创建对象时类构造函数完成初始化和其他相关操作;摧毁对象时析构函数完成清理工作(例如将构造函数分配的资源释放).

————————————2021-11-05-19:17————————————

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值