目录
一、构造函数
1.构造函数的样子
2.默认构造函数的特点
3.构造函数的使用
4.构造函数的用途
5.*思考题*
二、析构函数
1.析构函数的样子
2.析构函数的用途(什么时候需要自己手动写析构函数)
三、拷贝构造函数
1. 拷贝构造函数函数
2拷贝构造函数作用
3.*思考题*
四、深浅拷贝
1.浅拷贝
2.深拷贝
五、构造和析构顺序问题
*事例*
六、C++结构体
七、题目
(1).函数名和类名相同
(2).没有返回值
class Person
{
public:
Person(){}//构造函数--->没有返回值
protected:
string name;
int age;
};
注:如果不写构造函数,任何类中都存在一个默认构造函数
(1).默认的构造参数是无参的.
(2).当我们自己写了构造函数后,默认的构造函数就不存在了.
#include
#include
using namespace std;
class Person
{
public:
Person(string mName,int mAge)//构造函数
{
name = mName;
age = mAge;
}
void print()
{
cout <报错,因为自己定义了构造函数后默认构造函数不存在了
MM.print();
while (1);
return 0;
}
(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 <
(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 <
注意点:
● 即使不调用另一构造函数时,也可以这种方法,因此构造函数推荐使用初始化参数列表的写法.
● 只有构造函数有初始化参数列表的写法.(构造函数名(参数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;
};
(1).用来构造对象
(2).更多用于初始化成员数据(见以上代码)
(1).为什么不写构造函数可以构造对象?
这是因为存在一个默认的无参构造函数,所以可以构造无参对象.
(2).构造函数重载为了什么?
为了构造不同长相的对象.
(1).没有返回值
(2).没有参数
(3).函数名:~类名
class test{
public:
test(string mName, int mAge) :name(mName), age(mAge)
{
cout << "我是初始化参数列表的写法" << endl;
}
~test();//析构函数
protected:
string name;
int age;
};
注:
● 不写析构函数的话会存在默认的析构函数.
● 析构函数不需要自己 调用,对象死亡的之前会调用析构函数.
(1).当类中的数据成员是指针,并且动态申请内存就需要手写析构.
(2).析构函数用来释放数据成员申请动态内存.
#include
#include
#include
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). 拷贝构造函数也是构造函数,长相和构造函数一样的,只是参数是固定
● 拷贝构造函数唯一的参数是对对象引用
(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(); //此为拷贝构造
(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;
}
● 默认的拷贝构造叫做浅拷贝
● 拷贝构造函数中做了new内存操作,并且做拷贝赋值的操作
#include
#include
#include
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
#include
#include
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++结构体中加入构造函数后就可以当做类来看,只是默认属性为public,而类中默认属性为private.
#include
#include
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<//4.实现字符串比较
cout<//5.手写析构函数释放内存
#include
#include
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;
};