C++中的构造和解析

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没调好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值