04.03 【C++基础】C++类的六个默认成员函数

C++中,类有六个默认的成员函数,如图:

【C++基础】C++类的六个默认成员函数

接下来就分别介绍一下这六个成员函数

1.构造函数

在C++中,许多类的成员变量都是私有的,在类外部想要对变量初始化是办不到的,所有以必须有一个公有的函数进行初始化,而这个函数当且仅当在定义对象的时候自动执行一次,这时调用的函数叫做构造函数

构造函数是个比较特殊的成员函数,有以下几种特点:

1.函数名与类名相同

2.没有返回值

3.对象构造时系统自动调用对应的构造函数

4.构造函数可以重载

5.构造函数可以在类中定义,也可以在类外定义

6.如果类定义中没有给出构造函数,则C++的编译器会自动产生一个缺省的构造函数,但如果已定义则不会产生

7.无参的构造函数和全缺省的构造函数都是缺省的构造函数,缺省的构造函数只能有一个

无参的构造函数:

class Person{//假设名字是一个字符好了public: Person() {
_name = 'x';
_height = 188;
_weight = 150;
}private: char _name; int _height; int _weight;
};int main() {
Person p1;
Person p2();
}123456789101112131415161718

在类Person中有一个公有函数叫Person,没有参数,这就是无参的构造函数,注意,main函数中,第一个p1是调用了无参的构造函数,而第二个p2,编译器给出了一个警告:“Person p2(void)”: 未调用原型函数(是否是有意用变量定义的?)

所以这里没有调用构造函数定义出p2,注意这个错误

有参的构造函数:

class Person{ //假设名字是一个字符好了public: Person(char name, int high, int weight) {
_name = name;
_height = _height;
_weight = _weight;
}private: char _name; int _height; int _weight;
};int main() {
Persomn p3('q', 188, 150);//当然我肯定没这么高,也没有这么轻}1234567891011121314151617

上面的构造函数是有参数的,在初始化的时候传入参数,就调用成功了

再看一下缺省的构造函数,根据缺省程度可以分为全缺省和半缺省:

class Person{public:
//全缺省的构造函数 Person(char name = 'q', int height = 188, int weight = 150) {
_name = name;
_height = _height;
_weight = weight;
} //半缺省的构造函数
Person(char name, int height = 188, int weight = 150) {
_name = name;
_height = _height;
_weight = weight;
}private: char _name; int _height; int _weight;
};int main() {
Person p1;//调用缺省的构造函数
Person p2('q');//调用缺省的构造函数
system("pause"); return 0;
}1234567891011121314151617181920212223242526

【默认构造函数】

类如果没有显式定义构造函数时,编译器会合成一个默认的构造函数,该构造函数中什么工作都不做。只要显式定义了,即使该构造函数什么也不做,编译器也不会为该类合成默认的构造函数。编译器生成的默认构造函数使用与变量初始化相同的规则来初始化成员,具有类类型的成员通过运行各自的默认构造函数来进行初始化。

构造函数的作用主要是:

1、构建对象

2、初始化对象

3、类型转换

2.拷贝构造函数

在创建对象的时候用同类对象来进行初始化,这时候用的构造函数称为拷贝构造函数,拷贝构造函数是一种特殊的构造函数

有以下几点特征:

1.拷贝构造函数其实是一个构造函数的重载

2.拷贝构造函数的参数必须使用引用传参,不能使用传值传参

3.如果没有定义拷贝构造函数,系统会默认缺省的拷贝构造函数,缺省的拷贝构造函数会依次拷贝类成员进行初始化

代码如下:

class Person{public:
//全缺省的构造函数 Person(char name = 'q', int height = 188, int weight = 150) {
_name = name;
_height = _height;
_weight = weight;
}
Person(const Person& p) {
_name = p._name;
_height = p._height;
_weight = p._weight;
}private: char _name; int _height; int _weight;
};int main() {
Person p1;
Person p2(p1);
system("pause"); return 0;
}12345678910111213141516171819202122232425

这里用const是为了避免p1的值被修改,那么,为什么要用引用呢?

看引用之前,我们再看一种调用拷贝函数的方式,代码如下:

Person p3 = p1;1

上面这句也是一种使用拷贝函数的方式,那么如果使用值传递,C中,函数传递参数的时候有两种方式,一种是传值方式,一种是传址,但是这两种其实都是传值,在调用函数的时候对传入的参数进行拷贝然后压入函数的调用栈中,所以,如果是传值调用,就会出现这种情况:

p = p1;//注意这种情况,p为形参,p1为原值1

这种情况是不是跟上面调用拷贝函数的方式一样,那么接下来它就会继续调用拷贝构造函数,这样就会无限递归下去

注意,在大多数情况下,我们应该自己写出拷贝构造函数,即使系统会给我们合成它,因为系统生成的只是一种浅拷贝,比如:

char* str1 = "abcdef";char str2[7];12

上面的这样两个字符串数组,如果是我们自己拷贝,应该是一个一个对字符进行拷贝,如果是系统自动生成的默认拷贝函数,它就会直接复制,结果是str2也指向了str1的那串字符串,而不是去进行拷贝,这样就很可能出错

3.析构函数

在一个对象的声明周期结束时,编译器会自动调用一个成员函数,这个特殊的函数叫做析构函数,析构函数的特征如下:

1.析构函数名是在类名前加上字符~

2.析构函数无参数无返回值

3.一个类只有一个析构函数,若未定义则自动生成缺省的析构函数

4.对象的生命周期结束时,编译器自动调用析构函数

5.析构函数内部并不是删除对象而是在做一些清理工作

4.赋值操作符重载

研究赋值操作符重载之前,先搞清楚运算符重载是什么?

运算符重载的实质就是函数重载或函数多态。

运算符重载是一种形式的C++多态。目的在于让人能够用同名的函数来完成不同的基本操作。要重载运算符,需要使用被称为运算符函数的特殊函数形式

运算符函数形式:operator p(argument-list)//p为运算符

运算符函数的参数至少有一个必须是类的对象或者类的对象的引用。这种规定可以防止改变内置类型的函义。

以下5个不能重载的运算符:

. (成员访问运算符) .*(指针访问运算符) :: (与运算符) sizeof (大小运算符) ?: (条件运算符)

所以,赋值操作符重载的代码如下:

Person& operator=(Person& p) { /*
**这里面应该是具体的赋值
*/
return *this;
}123456

5.取地址操作符重载

Person& operator&() { return *this;
}1234

6.const修饰的取地址符重载

const Person& Person&() { return *this;
}123


分享到:


相關文章: