1构造函数
1.1构造函数的形式
函数名和类名相同
没有返回值
如果不写构造函数,任何类中默认存在一个构造函数,默认是无参的
当自己写了构造函数时,默认的构造函数就不再存在
构造函数在构造对象时调用
删除默认构造函数delete
指定使用默认的无参构造函数用default说明
允许构造函数调用另一个构造函数,只是要用初始化参数列表的写法
初始化参数列表:只有构造函数有
写法:构造函数名(参数1,参数2,........):成员1(参数1),成员2(参数2),......{}
1.2构造函数的作用
构造函数用来构造对象
构造函数更多用来初始化成员数据
#include <iostream>
using namespace std;
class student
{
public:
student()
{
cout << "这是无参构造函数,没有参数" << endl;
};//无参构造函数,在构造无参对象时会调用
//student() = delete;//删除默认的无参构造函数
student() = default;//指定使用默认的无参构造函数
student(string sname, int sage)
{
name = sname;
age = sage;
cout << "这是有参构造函数,有参数" << endl;
}//有参构造函数,在构造有参对象时会调用
void print()
{
cout << name << "\n" << age << endl;
}
protected:
string name = "zhangsan";
int age = 18;
};
//为了能够构造不同的对象,对构造函数进行缺省处理
class teacher
{
public:
teacher(string tname="", int tage = 20)
{
name = tname;
age = tage;
}//构造对象时,可构造无参数,只有一个参数,有两个参数的
//上面的构造函数与下面三行等效
//teacher() {};
//teacher(string tname) { name = tname; };
//teacher(string tname, int tage) { name = tname; age = tage; };
protected:
string name;
int age;
};
//初始化参数列表写法
class schoolmate
{
public:
schoolmate(string sname = "", int sage = 18) :name(sname), age(sage)
{
cout << "这是初始化参数列表写法" << endl;
//继承和类的组合必须采用初始化参数列表写法
}
protected:
string name;
int age;
};
//构造函数可以调用另一个构造函数初始化数据
class MM
{
public:
MM(string name,int age):name(name),age(age){}
MM() :MM("mo_ren", 18) {}//委托构造:允许构造函数调用另一个构造函数
MM() {}//没有给数据初始化,写出来就不叫默认构造函数了
void printdata()
{
cout << name << " " << age << endl;
}
protected:
string name;
int age;
};
int main()
{
student A;//报错,当自己写了构造函数或删除默认构造函数之后无法构建无参对象
//构造无参的对象,需要无参构造函数
student B("jodha", 18);//无无参构造函数可以构造有参对象
A.print();
teacher math;//缺省无参
teacher chinese("NAME");//缺省只有一个参
teacher english("NAMe", 20);//缺省有两个无参
//构造什么样的对象就需要什么样的构造函数
MM C("hhhh", 18);
C.printdata();
return 0;
}
2析构函数
形式&作用
无返回值,无参数,函数名::~类名
不写时也会存在默认的析构函数
析构函数不需要自己调用,对象死亡之前会调用析构函数
作用
当类中的数据成员是指针,并且动态申请内存时就需要手写析构函数
当函数用来释放数据成员申请的动态内存
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class student
{
public:
student(const char* pstr, int age) :age(age)
{
str = new char[strlen(pstr) + 1];
strcpy(str, pstr);
}
void printdata()
{
cout << str << " " << age << endl;
}
protected:
char* str;
int age;
};
student::~student()
{
cout << "这是析构函数" << endl;
delete[]str;
}
int main()
{
{
student A("JKDH", 18);
//A.~student();//手动调用析构函数,会导致二次调用
//在对象死亡前会调用析构函数,不算结束生命周期
//调用析构函数不会杀死对象
}//析构函数的调用
student B("ljdfb", 18);
B.printdata();
//new一个对象的时候,只有delete才会调用析构函数
{
student* pC = new student("jdhuf", 18);
delete pC; //用delete时会调用析构函数
pC = nullptr;
}
return 0;
}
3拷贝构造函数 (一个特殊的构造函数,形式和构造函数一致,但参数固定)
唯一的参数是 对对象引用
不写拷贝构造函数,也存在一个默认的拷贝构造函数
作用:通过一个对象去初始化另一个对象
调用拷贝构造:通过一个对象创建出一个新的对象时
当存在匿名队对象赋值操作时,咱要用const修饰
#include <iostream>
#include <string>
using namespace std;
class student
{
public:
student(string name, int age) :name(name), age(age) {}
void printdata()
{
cout << name << " " << age << endl;
}
//手写一个拷贝构造函数
student(const student& A) //student FA(A)
{ //参数加const为匿名对象的创建做准备
name = A.name; //FA.name=A.name
age = A.age; //FA.age=A.age
}
student() = default;
protected:
string name;
int age;
};
void print(student A)
{
cout << "拷贝构造" << endl;
A.printdata();
}
void print1(student& A)
{
A.printdata();
}
int main()
{
student A("kdon", 18);
A.printdata();
//显示调用
student FA(A);//通过一个对象去构造另一个对象
FA.printdata();
//隐式调用
student B = A;//拷贝构造
B.printdata();
//运算重载
student C;
C = A;
C.printdata();
//函数传参
print(A);
print1(A);
//无名对象 匿名对象
student temp;
temp= student("noname", 18);
temp.printdata();
//匿名对象创建时,拷贝构造一定要用const修饰
student temp = student("noname", 18);
return 0;
}
4深浅拷贝
浅拷贝:默认的拷贝构造叫浅拷贝,浅拷贝会引发析构问题(会重复释放内存)
#include <iostream>
#include <string>
using namespace std;
class student
{
public:
student(const char* sname, int age) :age(age)
{
name = new char[strlen(sname) + 1];
strcpy_s(name, strlen(sname) + 1, sname);
}
~student()
{
delete[]name;
}
student(const student& H)//即使自己写的也是浅拷贝,是赋值
{
name = H.name;
age = H.age;
}
void printdata()
{
cout << name << " " << age << endl;
}
protected:
char* name;
int age;
};
int main()
{
{
student A("lnlksn", 18);
student B(A);//浅拷贝
student C = A;//浅拷贝
//在此A的内存会被释放3次,导致崩溃
}
return 0;
}
深拷贝:重新new一次
#include <iostream>
#include <string>
using namespace std;
class student
{
public:
student(const char* sname, int age) :age(age)
{
name = new char[strlen(sname) + 1];
strcpy_s(name, strlen(sname) + 1, sname);
}
~student()
{
delete[]name;
}
student(const student& H)//自己写的深拷贝,再次new
{
name = new char[strlen(H.name) + 1];
strcpy_s(name, strlen(H.name) + 1, H.name);
age = H.age;
}
void printdata()
{
cout << name << " " << age << endl;
}
protected:
char* name;
int age;
};
int main()
{
{//没new,但释放3次
student A("lnlksn", 18);
student B(A);
student C = A;//A B C指向同一段内存
//在此A的内存会被释放3次,导致崩溃
}
//深拷贝不会崩溃,又new了一段内存
{
student A("lnlksn", 18);
student B(A);
student C = A;
}
return 0;
构造和析构顺序问题
普通对象,构造和析构的顺序是相反的
new出来的对象,delete会直接调用析构函数
ststic对象,当程序关闭的时候,生命周期才结束,所以最后释放
#include <iostream>
#include <string>
using namespace std;
class student
{
public:
student(string name, int age) :name(name), age(age)
{
cout << name << "\n" << age << endl;
}
~student()
{
cout << name << "\n" << age << endl;
}
student() = default;
protected:
string name;
int age;
};
int main()
{
{
student A("kfnsa", 18);
static student B("sdiucs", 18);//程序关闭时才会死亡,最后析构
student* pS = new student("ksahda", 18);
student HH[2];
delete pS;
pS = nullptr;
}
return 0;
}
输出:
kfnsa
18
sdiucs
18
ksahda
18
ksahda
18
-858993460
-858993460
kfnsa
18
sdiucs
18
C++结构体中的构造函数
#include <iostream>
#include <string>
using namespace std;
struct student
{
string name;
int age;
public:
student(string name, int age) :name(name), age(age)
{
cout << name << "\n" << age << endl;
}
student(const student& A)
{
name = A.name;
age = A.age;
cout << "浅拷贝构造";
}
~student()
{
}
};
int main()
{
//采用再创建时赋值的方式,也是调用构造函数
student A = { "osajh",18 };
cout << A.age << A.name;
student FA(A);
cout << FA.age << FA.name;
return 0;
}
尝试实现一些String类中的函数
#include <iostream>
#include <string>
#include <string.h>
#define _CRT_SECURE__NO_WARINGS
using namespace std;
class myString
{
public:
myString(const char* pstr)
{
str = new char[strlen(pstr) + 1];
strcpy_s(str, strlen(pstr) + 1, pstr);
}
~myString()
{
//cout << str << "Kill" << endl;
delete str;
str = nullptr;
}
myString(const myString&);//深拷贝,再次new
myString() = default;
const char* c_str();
const char* data();
const char* append1(myString&);
const char* compare(myString&);
protected:
char* str;
};
myString::myString(const myString& A)
{
str = new char[strlen(A.str) + 1];
strcpy_s(str, strlen(A.str) + 1, A.str);
}
const char* myString::c_str()
{
return str;
}
const char* myString::data()
{
return str;
}
const char* myString::compare(myString& STR)
{
if (str == STR.str) {
return "字符串相同";
}
if(str != STR.str) {
return "字符串不同";
}
}
const char* myString::append1(myString& STR)
{
strcat_s(str, strlen(str) + strlen(STR.str) + 1, STR.str);
return str;
}
int main()
{
{
myString str1;
myString str2("hhhh");
myString str3(str2);
myString str4 = str2;
cout << str2.c_str() << endl;
cout << str3.data() << endl;
myString strOne = "one";
myString strTwo = "two";
myString strThree = strOne.append1(strTwo);
cout << strThree.data() << endl;
cout << strOne.compare(strOne) << endl;
cout << strOne.compare(strTwo) << endl;
delete &str2;
delete &str3;
delete &str4;
}
return 0;
}
输出
hhhh
hhhh
onetwo
字符串相同
字符串不同
还有一些BUG没调好。