C++构造和析构
Posted 皓月肥波
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++构造和析构相关的知识,希望对你有一定的参考价值。
C++构造和析构
构造函数
-
构造函数长什么样子?
-
函数名和类名相同
-
没有返回值
-
如果不写构造函数,任何类中都存在一个默认的构造函数
-
默认的构造函数是无参的。
-
当我们自己写了构造函数,默认的构造函数就不存在
-
-
构造函数在构造对象的时候调用
-
delete可以用来删掉默认的函数
-
指定使用默认的无参构造函数,用default说明
-
允许构造函数调用另一个构造函数,只是要用初始化参数列表的写法
-
初始化参数列表 : 只有构造函数有
构造函数名(参数1,参数2,...):成员1(参数1),成员2(参数2),...
-
避免形参名和数据成员名相同的导致问题
-
-
-
构造函数干嘛的
-
构造函数用来构造对象
-
构造函数更多是用来初始化数据成员
-
-
思考题?
-
为什么不写构造函数可以构造对象? 是因为存在一个默认的无参构造函数,所以可以构造无参对象
-
构造函数重载为了什么? 为了构造不同长相的对象。
-
#include <iostream>
using namespace std;
class MM
public:
//MM() = delete; 如果没有构造函数再删掉默认的构造函数,则创建对象失败
MM(string mmName, int mmAge)
name = mmName;
age = mmAge;
cout << "带参构造函数" << endl;
//当有构造函数时,默认构造函数消失
MM() = default; //让有构造函数时存在默认无参构造函数
void print()
cout << name << " " << age << endl;
protected:
string name = "Lisa";
int age = 18;
;
//为了能够构造不同长相的对象,我们会给构造函数缺省处理
class Boy
public:
//Boy(string mname="", int mage=19)
//
// name = mname;
// age = mage;
//
//上面函数 等效可以实现下面三个函数的功能
Boy()
Boy(string mName) name = mName;
Boy(string mName, int mage) name = mName; age = mage;
protected:
string name;
int age;
;
string girlName = "Baby";
//初始化参数列表的写法
class Student
public:
Student(string mname = "", int mage = 20) :name(mname), age(mage)
//通过初始化参数列表的方式,形参给成员函数赋值
cout << "初始化参数列表" << endl;
//继承和类的组合必须采用初始化参数列表写法
Student(int mage) :name(girlName), age(mage) //当然可以通过外部变量赋值
protected:
string name;
int age;
;
//构造函数可以调用另一个构造函数初始化数据
class TT
public:
TT(string name, int age) :name(name), age(age)
//委托构造:允许构造函数调用另一个构造函数
TT() :TT("默认", 18) //没有给数据初始化
void print()
cout << name << "\\t" << age << endl;
protected:
string name;
int age;
;
int main()
//MM mm; 构造无参的对象,需要无参构造函数
MM mm("mm", 28);
mm.print();
MM girl;
girl.print();
Boy boy1;
Boy boy2("唐昊");
Boy boy3("唐三", 18);
TT tt;
tt.print();
return 0;
析构函数
-
析构函数长什么样子?
-
无返回值
-
无参数
-
函数名: ~类名
-
不写的话会存在默认的析构函数
-
析构函数不需要自己 调用,对象死亡的之前会调用析构函数
-
类外new一个对象的时候,只有delete 才会调用析构函数
-
-
析构函数用来干嘛?(什么时候需要自己手动写析构函数)
-
当类中的数据成员是指针,并且动态申请内存就需要手写析构
-
析构函数用来释放数据成员申请动态内存
#include <iostream> #include <string> #include <cstring> using namespace std; class MM public: MM(const char* pstr, int age) :age(age) str = new char[strlen(pstr) + 1]; strcpy(str,pstr); //拷贝在<cstring> //strcpy_s(str, strlen(pstr) + 1, pstr); void print() cout << str << "\\t" << age << endl; ~MM(); protected: char* str; int age; ; MM::~MM() cout << "我叫做析构函数" << endl; delete[] str; int main() MM mm("唐昊", 55); //mm.~MM(); //手动调用会导致二次释放问题 mm.print(); cout << "主函数" << endl; //new一个对象的时候,只有delete 才会调用析构函数 MM* p = new MM("唐三", 18); delete p; p = nullptr; return 0;
拷贝构造函数
-
拷贝构造函数也是构造函数,长相和构造函数一样的,只是参数是固定
-
拷贝构造函数唯一的参数是对对象引用
-
-
不写拷贝构造函数,也存在一个默认的拷贝构造函数
-
拷贝构造函数作用: 通过一个对象去初始化另一个对象
-
问题?
-
什么时候调用拷贝构造?
-
当通过一个对象去创建出来另一个新的对象时候需要调用拷贝
-
-
拷贝构造什么时候需要加const修饰参数?
-
当存在匿名对象赋值操作的时候,必须要const修饰
-
#include <iostream> #include <string> using namespace std; class MM public: MM() = default; //不写则不存在默认构造函数 MM(string name, int age) :name(name), age(age) void print() cout << name << "\\t" << age << endl; MM(const MM& mm) //MM girl(mm); name = mm.name; age = mm.age; cout << "拷贝构造" << endl; protected: string name; int age; ; void printData(MM mm) //MM mm=实参; mm.print(); void printData2(MM& mm) //不存在拷贝本引用不调用拷贝函数 mm.print(); int main() MM mm("唐三", 20); mm.print(); //显示调用调用 cout << "显示调用调用" << endl; MM boy(mm); //通过一个对象创建另一个对象 boy.print(); //隐式调用 cout << "隐式调用" << endl; MM boy2 = mm; //拷贝构造 boy2.print(); MM boy3; boy3 = mm; //运算符重载拷贝不调用拷贝构造函数 boy3.print(); //函数传参 cout << "第一种调用形态" << endl; printData(mm); cout << "第二种调用形态" << endl; printData2(mm); //无名对象 匿名对象 MM temp; temp = MM("匿名", 18); temp.print(); //匿名对象创建对象时候,拷贝构造一定要用const修饰 MM temp2 = MM("匿名", 199); return 0;
构造和析构顺序问题
-
普通对象,构造顺序和析构顺序是相反
-
new出来的对象,delete会直接调用析构函数
-
static对象,当程序关闭的时候,生命周期才结束,所以是最后释放
-
#include <iostream> #include <string> using namespace std; class MM public: MM(string name="x") :name(name) cout << name; ~MM() cout << name; protected: string name; ; int main() MM mm1("A"); //A static MM mm2("B"); //B 程序关闭时候才死亡,最后析构 MM* p3 = new MM("C"); //C MM mm4[4]; //xxxx delete p3; //C delete 直接调用析构 p3 = nullptr; //xxxxAB //ABCxxxxCxxxxAB return 0;
C++结构体
#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 = "唐三",20; 错误,因为没有两个参数的构造函数 MM object = "唐三" ; cout << object.name << "\\t" << object.age << endl; //C++结构体一旦写了构造函数,就必须按照C++类的方式的去用 MM mm(object); cout << mm.name << "\\t" << mm.age << endl; return 0;
-
作业
#include <iostream>
#include <cstring>
using namespace std;
class mystring
public:
mystring(const char* pstr = "")
strSize = strlen(pstr) + 1;
str = new char[strSize];
strcpy_s(str, strSize, pstr);
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;
//
char* append(const mystring& object)
return strcpy(str, object.str);
int compare(const mystring& object)
return strcmp(str, object.str);
~mystring()
delete[] str;
str = nullptr;
protected:
char* str; //需要存储
int strSize;
;
int main()
//1.实现string中创建方式
mystring str1;
mystring str2("ILoveyou");
mystring str3(str1);
mystring str4 = str2;
//2.通过实现data和c_str函数 打印字符串
cout << str2.c_str() << endl; //打印ILoveyou
cout << str2.data() << endl; //打印ILoveyou
//3.实现append 实现字符串的链接
mystring strOne = "one";
mystring strTwo = "two";
mystring strThree = strOne.append(strTwo);
cout << strThree.data() << endl; //onetwo
//4.实现字符串比较
cout << strOne.compare(strOne) << endl; //0
//5.手写析构函数释放内存
return 0;
以上是关于C++构造和析构的主要内容,如果未能解决你的问题,请参考以下文章