C++构造和析构函数

目录

一、构造函数

        1.构造函数的样子

        2.默认构造函数的特点

        3.构造函数的使用

        4.构造函数的用途

        5.*思考题*        

二、析构函数

        1.析构函数的样子

        2.析构函数的用途(什么时候需要自己手动写析构函数) 

三、拷贝构造函数 

        1. 拷贝构造函数函数

         2拷贝构造函数作用

        3.*思考题*

四、深浅拷贝   

        1.浅拷贝

        2.深拷贝

五、构造和析构顺序问题

   *事例*        

六、C++结构体

 七、题目


一、构造函数

        1.构造函数的样子

                (1).函数名和类名相同

                (2).没有返回值

class Person
{
public:
	Person(){}//构造函数--->没有返回值
protected:
	string name;
	int age;
};

        注:如果不写构造函数,任何类中都存在一个默认构造函数

        2.默认构造函数的特点

                (1).默认的构造参数是无参的.

                (2).当我们自己写了构造函数后,默认的构造函数就不存在了.

#include<iostream>
#include<string>
using namespace std;
class Person
{
public:
	Person(string mName,int mAge)//构造函数
	{
		name = mName;
		age = mAge;
	}
	void print()
	{
		cout <<name << "\t" << age << endl;
	}
protected:
	string name;
	int age;
};
int main()
{
	Person MM = { "Miss Du", 19 };//自己定义构造函数后可以赋值
	//Person GG; --->报错,因为自己定义了构造函数后默认构造函数不存在了
	MM.print();
	while (1);
	return 0;
}

        3.构造函数的使用

                (1).构造函数在构造对象的时候使用.

                (2).delete可以删掉默认构造函数.

class test{
public:
	test() = delete;//删除默认构造函数
protected:
	string name;
	int age;
};
int main()
{
	//test mm;--->无法构造,因为默认构造函数已经删除    构造无参的对象,需要无参构造函数
	while (1);
	return 0;
}

                (3).当自己写了构造函数后还想使用默认构造函数,可以用default说明.

class Person
{
public:
	Person(string mName,int mAge)
	{
		name = mName;
		age = mAge;
	}
	Person() = default;//默认构造函数仍可使用
	void print()
	{
		cout <<name << "\t" << age << endl;
	}
protected:
	string name;
	int age;
};
int main()
{
    Person MM = { "Miss Du", 19 };//自己定义构造函数后可以赋值
	Person GG; //仍然可以调用默认构造函数
	MM.print();
	GG.print();
    while(1);
    return 0;
}

                (4).允许构造函数调用另一个构造函数,只是要用初始化参数列表的写法.(推荐)

class Person
{
public:
	/*Person(string mName,int mAge)
	{
		name = mName;
		age = mAge;
	}*/
	//等价于上面这种写法
	Person(string mName,int mAge):name(mName),age(mAge)
	{
		cout << "我是初始化参数列表的写法" << endl;
	}
	Person() = default;//默认构造函数仍可用
	void print()
	{
		cout <<name << "\t" << age << endl;
	}
protected:
	string name;
	int age;
};

   注意点:

         ●  即使不调用另一构造函数时,也可以这种方法,因此构造函数推荐使用初始化参数列表的写法.    

        ●  只有构造函数有初始化参数列表的写法.(构造函数名(参数1,参数2,...):成员1(参数1),成员2(参数2),...{} )---->成员中的参数也可以使用全局变量来赋值.

        ●  可以避免形参名和数据成员名相同的导致问题.    

string baby="baby";
class test{
public:
	test() = delete;
	test(int mAge) :name(baby), age(mAge){}
    //等价于下面
    test(stirng mName,int mAge):name(mName),age(mAge){}
protected:
	string name;
	int age;
};

        4.构造函数的用途

                (1).用来构造对象

                (2).更多用于初始化成员数据(见以上代码)

        5.*思考题*        

                (1).为什么不写构造函数可以构造对象?

                        这是因为存在一个默认的无参构造函数,所以可以构造无参对象.

                (2).构造函数重载为了什么?

                        为了构造不同长相的对象.

二、析构函数

        1.析构函数的样子

                (1).没有返回值

                (2).没有参数

                (3).函数名:~类名

class test{
public:
	test(string mName, int mAge) :name(mName), age(mAge)
	{
		cout << "我是初始化参数列表的写法" << endl;
	}
	~test();//析构函数
protected:
	string name;
	int age;
};

        注:

                ● 不写析构函数的话会存在默认的析构函数.

                ● 析构函数不需要自己 调用,对象死亡的之前会调用析构函数. 

        2.析构函数的用途(什么时候需要自己手动写析构函数) 

                (1).当类中的数据成员是指针,并且动态申请内存就需要手写析构.

                (2).析构函数用来释放数据成员申请动态内存. 

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
class Person
{
public:
	Person(const char*mName,int mAge) :age(mAge)
	{
		name = new char[strlen(mName) + 1];
		strcpy(name, mName);
	}
	void print()
	{
		cout << name << "\t" << age << endl;
	}
	/*~Person()
	{
		cout << "我是析构函数" << endl;
		delete[] name;
	}*/
	//等价于下面
	~Person();//类中声明,类外定义
protected:
	char* name;
	int age;
};
Person::~Person()
{
	cout << "我是析构函数" << endl;
	delete[] name;
}
int main()
{
	{
		Person MM("Miss Du", 19);
		MM.print();
	}
	cout << "主函数" << endl;
	while (1);
	return 0;
}

三、拷贝构造函数 

        1. 拷贝构造函数函数

                 (1). 拷贝构造函数也是构造函数,长相和构造函数一样的,只是参数是固定

                        ● 拷贝构造函数唯一的参数是对对象引用

                 (2). 不写拷贝构造函数,也存在一个默认的拷贝构造函数

         2拷贝构造函数作用

                        ● 通过一个对象去初始化另一个对象         

class Person
{
public:
	Person(string mName, int mAge) :name(mName), age(mAge){}
	void print()
	{
		cout << name << "\t" << age << endl;
	}
	//拷贝构造
	Person(Person& MM){							//Person mm(MM)
		name = MM.name;							//mm.name=MM.name
		age = MM.age;							//mm.age=MM.age
		cout << "我是拷贝构造函数" << endl;
	}
protected:
	string name;
	int age;
};
int main()
{
	Person MM("Miss Du", 19);
	MM.print();
	//显式拷贝
	cout << "显式拷贝" << endl;
	Person mm(MM);        //通过一个对象创建另一个对象
	mm.print();
	//等价于下面 --->隐式调用
	/*Person mm = MM;
	mm.print();*/
	while (1);
	return 0;
}

        注:区别运算符重载和拷贝函数

    Person girl;
	girl = MM;
	girl.print();    //此为运算符重载  不会调用拷贝函数 相当于赋值


    Person mm(MM);
	mm.print();    //此为拷贝构造

        3.*思考题*

                (1).什么时候调用拷贝构造?

                        ● 当通过一个对象去创建出来另一个新的对象时候需要调用拷贝

                (2).拷贝构造什么时候需要加const修饰参数?

                        ● 当存在匿名对象赋值操作的时候,必须要const修饰

                注:因此在写拷贝构造函数时一般都会加上const

    //匿名对象 无名对象
	Person GG = Person("Mr Yan", 19);
	GG.print();
	//匿名对象创建对象时候,拷贝构造一定要用const修饰
    Person temp;
	temp = Person("匿名", 18);
	temp.print();

                (3).函数传参

void printData(Person MM) //Person MM=实参 
{
	MM.print();
}
void printData2(Person& MM) //不存在拷贝本
{
	MM.print();
}
int main()
{
    Person MM("Miss Du", 19);
    printData(MM);     //调用了拷贝构造函数
	printData2(MM);    //没有调用
    while(1);
    return 0;
}

四、深浅拷贝   

        1.浅拷贝

                ● 默认的拷贝构造叫做浅拷贝

        2.深拷贝

                ● 拷贝构造函数中做了new内存操作,并且做拷贝赋值的操作

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
class Person
{
public:
	Person() = default;
	Person(const char* mName, int mAge) :age(mAge)
	{
		name = new char[strlen(mName) + 1];
		strcpy(name, mName);
	}
	Person(const Person& MM)
	{
		//name = object.name;
		name = new char[strlen(MM.name) + 1];//需要深拷贝
		strcpy(name , MM.name);
		age = MM.age;
	}
	void print()
	{
		cout << name << "\t" << age << endl;
	}
	~Person()//自己写的析构函数
	{
		delete[] name;
	}

protected:
	char* name;
	int age;
};
int main()
{
	Person MM("Miss Du", 19);
	Person girl(MM);
	Person gm = MM;
	girl.print();
	gm.print();
	while (1);
	return 0;
}

五、构造和析构顺序问题

        (1).普通对象构造和析构顺序是相反的.

        (2).new出来的对象,delete会直接调用析构函数.

        (3).static对象,当程序关闭的时候,生命周期才结束,所以是最后释放.

   *事例*        

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
class Person
{
public:
	Person(string name = "x") :name(name) {
		cout << name;
	}
	~Person(){
		cout << name;
	}
protected:
	string name;
};
int main()
{
	{
		Person MM1("A");                    //A
		static Person MM2("B");             //B
		Person* MM3 = new Person("C");      //C
		Person MM4[4];                      //XXXX
		delete MM3;                         //C
		MM3 = nullptr;
	}                                       //XXXXA
	while (1);
	return 0;                               //B
}//最后答案:ABCXXXXCXXXXAB

六、C++结构体

                ● C++结构体中加入构造函数后就可以当做类来看,只是默认属性为public,而类中默认属性为private.

#include <iostream>
#include <string>
using namespace std;
struct MM 
{
	//默认为公有属性
	//类中默认属性是私有属性
//protected:
	string name;
	int age;
public:
	MM(string name) :name(name) 
	{
		cout << "构造函数" << endl;
	}
	MM(const MM& object) 
	{
		name = object.name;
		age = object.age;	
		cout << "拷贝构造" << endl;
	}
	~MM() 
	{

	}
};
int main() 
{
	//采用创建时候赋值的方式,也是调用构造函数
	//MM object = { "lisa",19 };  错误,因为没有两个参数的构造函数
	MM  object = { "lisa" };
	cout << object.name << "\t" << object.age << endl;
	//C++结构体一旦写了构造函数,就必须按照C++类的方式的去用
	MM mm(object);
	cout << mm.name << "\t" << mm.age << endl;
	return 0;
}

 七、题目

        ● 自己手写一个string类,满足以下功能                             

//1.实现string中创建方式
    string str1;
    string str2("ILoveyou");
    string str3(str1);
    string str4 = str2;
//2.通过实现data和c_str函数 打印字符串
    cout << str2.c_str() << endl;  //打印ILoveyou
    cout << str2.data() << endl;   //打印ILoveyou
//3.实现append 实现字符串的链接
    string strOne="one";
    string strTwo="two";
    string strThree=strOne.append(strTwo);
    cout<<strThree.data()<<endl;        //onetwo
//4.实现字符串比较
    cout<<strOne.compare(strOne)<<endl;    //0
//5.手写析构函数释放内存                                                                                                       

#include <iostream>
#include <cstring>
using namespace std;
class mystring
{
public:
	//mystring() 
	//{
	//	strSize = 1;
	//	str = new char;
	//	*str='\0';
	//};
	mystring(const char* str="") 
	{
		strSize = strlen(str) + 1;
		mystring::str = new char[strSize];
		strcpy_s(mystring::str,strSize,str);
	}
	mystring(const mystring& object)
	{
		strSize = object.strSize;
		str = new char[strSize];
		strcpy_s(str, strSize, object.str);
	}
	char* c_str() 
	{
		return str;
	}
	char* data() 
	{
		return str;
	}
	mystring append(const mystring& object)
	{
		mystring temp;
		temp.strSize = mystring::strSize + object.strSize-1;
		temp.str = new char[temp.strSize];
		memset(temp.str, 0, temp.strSize);
		strcat_s(temp.str, temp.strSize, str);
		strcat_s(temp.str, temp.strSize, object.str);
		return temp;
	}
	int compare(const mystring& object) 
	{
		return strcmp(str, object.str);
	}
	~mystring()
	{
		delete[] str;
		str = nullptr;
	}
protected:
	char* str;			//需要存储
	int  strSize;		
};

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值