构造函数详解

 一、核心作用

简单来讲就是一句话:初始化对象的数据成员


四种典例

典例一(无参构造函数)------MyStr str;

MyStr(){
    name=NULL;
    cout<<"Default constructor"<<endl;
}

典例二 (有参构造函数)------MyStr str(..........);

MyStr(int _id,const char *_name){
    cout<<"Constructor"<<endl;
    id=_id;
    name=new char[strlen(_name)+1];
    if(name!=NULL)
        strcpy(name,_name);    //strcpy_s(name,strlen(_name)+1,_name);

 典例三(拷贝构造函数)------MyStr str2=str;(这里的str是指前面已经定义过的str)

MyStr(const MyStr &str){
    cout<<"Copy constructor"<<endl;
    id=str.id;
    name=new char[strlen(str.name)+1];
    if(name!=NULL)
        strcpy(name,str.name);    //strcpy_s(name,strlen(str.name)+1,s.name);

典例四(析构函数)-------格式为:~类名(){函数体}

~MyStr(){delete []name;}

这里指的是释放name的数组空间。 


然后浅浅复习一下这个new:

顾名思义其实就是开辟一个新的空间,在这里我们给它new了一个字符数组,由于name是指针,new完之后就是指向这个字符数组的首地址。(其实可以理解成为这是一个类外初始化数组在类内的体现方式)。

还有strcpy:

这是在C++string库中的一员,作用是字符串拷贝。和strcpy_s的区别是strcpy_s更加安全,因为加了第三个参数长度,可以有效防止溢出。

错误代码:

#include<iostream>
#include<cstring>
using namespace std;
int main(){
	char str1[3]="abc";
	char str2[5]="hello";
	strcpy(str1,str2);      //error: initializer-string for 'char [5]' is too long
	cout<<str1;
	return 0;
}

 但是得注意有些编译器无法使用strcpy_s这个函数


二、特点及注意点

1.名字与类名相同,无返回值。(意思就是在MyStr()前面不要加东西)

2.如果定义类时没有写构造函数,系统会生成一个默认的无参构造函数,默认构造函数没有参数,不做任何工作。如果定义了构造函数,系统不再生成默认的无参构造函数。(这个时候如果调用了无参的构造函数就会报错)

3.带有默认参数的构造函数,在实例化时若传入参数,则传入的参数值优先;若没有传入参数,则就使用指定的默认参数。

MyStr(int _id=100,const char *_name="hhxx"){}

如上,当没有传入参数时,_id=100,*_name="hhxx",但若有参数传入则按照传入的参数来。 

4.关于“;”这个符号(个人之前会搞错):由于MyStr是一个类,所以在最外层定义完类之后需要加 ";"。但是构造函数的花括号后面";"加不加编译都能通过。

这里还要注意一个用初始化列表写法的标点 :

//这里假设类里面有int a,b,c;三个成员变量,然后有一个构造函数
MyStr(int _a,int _b,int _c):a(_a),b(_b),c(_c){}

5.通常我们的构造函数都放在类的public中。这里复习一下public、protected、private三者的区别: 

public://类外访问
protected://派生类访问
private://类内和友元访问

 

三、基本用法

我把PPT上的代码搬过来了

#include<iostream>
#include<cstring>
using namespace std;
class MyStr
{
    char *name;
    int id;
public:
    MyStr(){
        name=NULL;
        cout<<"Default constructor"<<endl;
    }
    MyStr(int _id,const char *_name){
        cout<<"Constructor"<<endl;
        id=_id;
        name=new char[strlen(_name)+1];
        if(name!=NULL)
            strcpy(name,_name);    //strcpy_s(name,strlen(_name)+1,_name);
    }
    /*
    MyStr(int _id,const char *_name):id(_id){
        cout<<"Constructor"<<endl;
        name=new char[strlen(_name)+1];
        if(name!=NULL)
            strcpy(name,_name);    //strcpy_s(name,strlen(_name)+1,_name);
    }
    */
    MyStr(const MyStr &str){
        cout<<"Copy constructor"<<endl;
        id=str.id;
        name=new char[strlen(str.name)+1];
        if(name!=NULL)
            strcpy(name,str.name);    //strcpy_s(name,strlen(str.name)+1,s.name);
    }
    ~MyStr(){delete []name;}
};
int main()
{
    MyStr str1(1,"hhxx");
    cout<<"====================="<<endl;
    MyStr str2;
    str2=str1;
    cout<<"====================="<<endl;
    MyStr str3=str2;
    return 0;
}

下面是输出的代码: 

 


拷贝构造函数 

拷贝构造函数中有以下几个要点:

1.const的作用:确保在拷贝构造函数中不会修改传入对象的内容。

2.“&”符号的作用:防止循环调用。(如果没有这个符号将报错)

3.用“对象.变量”的方式调用引用中的内容。

4.拷贝赋值和拷贝构造函数的联系:

MyStr &operator=(const MyStr &str){
    cout<<"Assignment operator"<<endl;
    if(this==&str)
        return *this;
    id=str.id;
    delete []name;
    name=new char[strlen(str.name)+1];
    if(name!=NULL)
        strcpy(name,str.name);    //strcpy_s(name,strlen(str.name)+1,s.name);
    return *this;
};

这段代码的作用跟拷贝构造函数是一样的,简单理解就是这里把”=“重载了,本来的等号是浅拷贝,这里把它重载成为深拷贝。

如果在class中加入这一段代码,则最后输出变为:


  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值