一、核心作用
简单来讲就是一句话:初始化对象的数据成员
四种典例
典例一(无参构造函数)------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中加入这一段代码,则最后输出变为: