C++类之构造函数

C++的构造函数


一、什么是构造函数


在C++中构造函数是类的默认六大成员之一,即我们创建一个空类,里面什么成员都没有,C++也会为这个空类生成6个默认的成员函数,构造函数就是其中之一

构造函数虽然取名构造,但它并不是用来构造对象,申请内存空间的,它的主要工作其实是完成对象的初始化工作

在C语言中,我们通常会为一个struct设置init函数来进行初始化,但是这样非常繁琐,而且容易遗忘。

在C++中针对这一情况做出了改善,就为每个类都添加了构造函数。

二、构造函数的特性


构造函数是C++中每个类都有的特殊的成员函数,要注意它的作用是初始化对象,它有下面几个特征:

函数名称与类名相同
无返回值
创建类类型的对象时(对象实例化时)由编译器自动调用,保证每个数据成员都有一个合适的初始值;
在该对象的整个生命周期中只会调用一次;
构造函数支持函数重载。

class Student{
private:
    int _no;//学号
    string _name;//姓名
    int _age;//年龄
    
public:
    Student(){
        //无参构造函数
    }

    Student(int no, string name, int age){
        //有参构造函数
        _no = no;
        _name = name;
        _age = age;
    }
};
int main(){
	Student s1;//这里调用的是无参的构造函数
    Student s2(1, "zhangsan", 20);//这里调用有参的构造函数
    //特别注意在s1这里,调用无参构造函数在s1后面务必不能加括号!!!否则就变成了函数声明!!!
    //Student s3() 这个的含义是声明一个函数,函数名称叫s3,它的返回值是一个Student对象!
    return 0
}

三、默认构造函数

假如在一个类中,程序员没有显式地为其定义一个构造函数,那么编译器就会自动生成一个无参的默认构造函数,一旦用户自己定义了构造函数,那么编译器就不会再生成默认的构造函数了。

class Student{
public:
    //这里用户没有自己定义构造函数
private:
    int _no;
    string _name;
    int _age;
};

int main(){
    Student s;//虽然没有定义构造函数,但是编译器自动生成了无参的默认构造函数,所以这里也可以成功地创建对象
    return 0;
}

明显可以看出s的三个数据成员都被初始化了,int使用的随机值,而string则使用了空字符串。

重点是这个由编译器自动生成的无参的默认构造函数有一个规则:

对于该类的内置数据类型(int、double、char、指针等),不做处理(所以上面我们看到int就是随机值);自定义类型(struct、class),去调用自定义类型自己的无参构造函数来初始化。

打个比方,我们的Student类中还有一个类A

class A{
public:
    A(int a0, int a1){
    	_a0 = a0;
        _a1 = a1;
    }
private:
    int _a0;
    int _a1;
}
class Student{
private:
    int _no;
    string _name;
    int _age;
    A _a;//Student内部有一个自定义类型A
};
int main(){
    Student s;
    return 0;
}

class A {
private:
	int _a0;
	int _a1;
public:
	A(int a0, int a1) {//A的构造函数不是默认的构造函数,是个有参的构造函数!
		_a0 = a0;
		_a1 = a1;
	}
};
class Student {
public:
	Student(){}//无参的默认构造函数
private:
	int _no;
	string _name;
	int _age;
	A _a;//自定义的A类型
};
int main() {
	Student s;
	return 0;
}

这里其实是C++在早期语法设计时候的一种失误,这种特定的机制导致在初始化带有自定义类型的类时非常麻烦,也给初学者带来了不少难度,所以在C++11标准中专门为初始化引入了一种新的规则,可以在成员变量定义的时候直接给缺省值,这样就不需要在构造函数中指明了,但是这里也容易混淆,也是一个重点:这里的缺省值,只是声明,并没有开辟空间,而非初始化,因为初始化是已经开辟空间之后,才要对已有的空间进行初始化。就如同函数的缺省值一样,如果在对象实例化时,我们没有特别指明,就用这个缺省值来初始化!

class A {
private:
	int _a0 = 0;//缺省值
	int _a1 = 1;//缺省值
public:

};
class Student {
public:

private:
	int _no = 111;//缺省值111
	string _name = "zhangsan";//缺省值
	int _age = 20;//缺省值
	A _a;
};
int main() {
	Student s;
	return 0;
}

四、默认构造函数与无参构造函数的关系


默认构造函数包含三个:分别是无参构造函数、全缺省构造函数、编译器自动为我们生成的构造函数。

它们的共性是都没有参数,即我们不需要传入任何参数就可以进行调用。但是默认构造函数只能有一个,编译器自动为我们生成的构造函数与其余两个不能同时出现,因为只要程序员自己定义了构造函数,编译器就不会自动生成了,所以只有当我们什么都不写的时候,编译器自动生成的默认构造函数是唯一存在的,这并不难理解;但是无参构造函数和全缺省构造函数,我们只能写一个,虽然它俩之间构成了函数重载,但是它们并不能同时存在,因为它们都不需要传入参数,如果我们调用了默认构造函数,那该调用它们两个之间的谁呢?这里就会给编译器产生歧义。所以如果程序员要自己显式地给出默认构造函数,只能在无参的默认构造函数和全缺省的默认构造函数之中选择一个。

class Student{
private:
    int _no;
    string _name;
    int _age;
public:
    //这两种默认构造函数只能同时存在一种
    /*Student(){
        _no = 111;
        _name = "zhangsan";//无参构造
        _age = 18
    }*/
    
    Student(int no = 111, string name = "zhangsan", int age = 18){
    	_no = no;
        _name = name;//全缺省构造
        _age = age;
    }
};

 有的人会认为,只有我们自己不写,编译器自动生成的构造函数才叫默认构造函数,经过上面的分析,我们就可以明确,这种观点是不正确的,只要是无需参数就可以调用的构造函数,都可以用作默认构造函数,但是默认构造函数只能有一个!不能同时存在多个默认构造函数!

                        
参考链接:https://blog.csdn.net/weixin_45523353/article/details/123216917

  • 40
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值