第4节课:9.3:构造析构
一、构造函数
1.构造函数是什么:
给类数据成员赋值的,也就是或初始化类的对象
(如果为私有数据成员,不像结构体那样可以在定义的时候直接给值初始化)
2.构造函数的定义方法:Stu()
1.名字与类名相同
2.没有返回值类型(void)也不行
3.函数体为赋值逻辑
4.有参数列表(对外接口)
3.使用方法:
1.调用时机:自动调用
在定义类的对象的时候,或者动态开辟的时候,
class Stu
{
int num;
public:
int a;
Stu();
};
Stu::Stu()
{
num = 1;
a = 2;
}
int main()
{
Stu stu;
Stu * p = new Stu;//可以打断点调试
return 0;
}
2.构造函数的重载(无参构造和带参构造)
1.重载的参数列表不同,函数体不同
2.注意:当类中定义了带参构造函数后,不可以Stu stu;定义会报错,不会调用系统默认的构造函数,系统不会提供默认构造函数了
也就是说不能用默认的构造方式初始化对象(系统的默认构造函数什么也不做)
class Stu
{
int num;
public:
int a;
Stu();
Stu(int i);
};
Stu::Stu()//无参构造函数
{
num = 1;
a = 2;
}
Stu::Stu(int i)//带参构造函数
{
num = 1;
a = 2;
}
int main()
{
Stu stu;//调用无参构造函数
Stu stu2(1);//调用带参构造函数
Stu * p = new Stu(1);//调用带参构造函数
return 0;
}
//注意:当类中定义了带参构造函数后,不可以Stu stu;会报错,不会调用系统默认的构造函数
二、拷贝构造函数
1.是什么?
用一个对象给另外一个对象初始化,或者是实参和形参(形参为类的对象)结合的时候
2.定义?(const Stu& other)
是一种特殊的函数,函数名与类名相同,参数列表(const Stu& other)只能传引用,不能传值不然死循环,报错
3.使用:
1.系统默认的拷贝构造函数
系统有默认的拷贝构造函数,隐式调用但是与默认的构造函数不同的是,形参列表不同(不是什么都不做)
默认拷贝是浅拷贝。(也就是说两个对象从数据成员指向同一块内存区域)
举个栗子:
class Stu
{
int num;
int a;
char* name;
public:
Stu(int i);
}
Stu::Stu(int i)
{
num = i;
a = 2;
name = "chi";
}
int main()
{
Stu stu1(1);
Stu stu2(stu1);//调用默认的,stu2的值与stu1的值一模一样
}
2.浅拷贝和深拷贝:什么时候需要重写拷贝构造?
从上面的例子知道:stu1和stu2的name的指针的值是一样的
#include <stdio.h>
#include <string>
using std::string;
//#include <string>
class Stu
{
int num;
int a;
char* name;
public:
Stu(int i);
void print()
{
printf("%d\n",num);
printf("%s\n",name);
}
//拷贝
Stu(const Stu& other);
};
Stu::Stu(int i)
{
num = i;
a = 2;
name = "chi";
}
Stu::Stu(const Stu& other)
{
//深层构造
a = other.a;
num = other.num;
//name = other.name;
/*
*/
if (other.name == NULL)
{
name = NULL;
}
else
{
//strcpy(name,other.name);
char* pnew = new char[strlen(other.name) + 1];
for (size_t i = 0; i < strlen(other.name); i++)
{
pnew[i] = other.name[i];
}
pnew[strlen(other.name)] = '\0';
name = pnew;
}
}
int main()
{
Stu stu1(1);
Stu stu2(stu1);
stu2.print();
}
举个栗子2:在开辟动态内存时
class Stu
{
int num;
int a;
char* name;
public:
Stu(int i);
void print()
{
printf("%d\n",num);
printf("%s\n",name);
}
//拷贝
//Stu(const Stu& other);
~Stu(){delete name;}
};
Stu::Stu(int i)
{
num = i;
a = 2;
name = "chi";
}
int main()
{
Stu stu1(1);
Stu stu2(stu1);//调用默认的拷贝,为浅拷贝,只是简单的赋值
//stu2.name == stu1.name 指向同一地方
return 0;
}
画图;
3调用时机:
1.形参为类的对象的时候,实参和形参结合,形参会调用自己默认的拷贝构造函数
2.函数的返回值类型为类的对象
举个例子:以后再举例子
三、析构函数
1.是什么·?
在类对象生命周期结束的时候,系统自动调用它释放对象
2.定义?~Stu()。,。
函数名为类名 + ~ ,没有返回值类型,
(类比:杯子装水可乐啥的,装东西就是调用构造函数
倒东西就是调用析构函数,不需要知道倒的是什么东西,
所以析构函数没有参数列表,也不能够重构)
3.使用方法:
1.析构函数在一个类中只能够有唯一一个?
不能够重构析构函数
2.调用时机
对象死亡时自动调用(return 0;时还有一种情况是动态释放对象会调用析构函数
3.常见错误:delete释放栈区内存导致错误
#include <stdio.h>
#include <string>
class Stu
{
int num;
char* name;
public:
Stu(char* n);
~Stu();
Stu(const Stu& other);//拷贝
};
Stu::Stu(char* n)
{
if (n != NULL)
{
name = n;
}
else
name = NULL;
}
Stu::~Stu()
{
if (name)
delete[] name;
name = NULL;
}
Stu::Stu(const Stu& other)
{
num = other.num;
if (other.name!=NULL)
{
name = new char[strlen(other.name) + 1];
strcpy(name,other.name);
}
else
name = NULL;
}
int main()
{
Stu stu1("chj");
Stu stu2(stu1);
return 0;
}
4.修改后的代码:
#include <stdio.h>
#include <string>
class Stu
{
int num;
char* name;
public:
Stu(char* n);
~Stu();
Stu(const Stu& other);//拷贝
};
Stu::Stu(char* n)
{
if (!n)
{
name = new char[strlen(n) + 1];
strcpy(name,n);
}
else name = NULL;
}
Stu::Stu(const Stu& other)
{
num = other.num;
if (other.name)
{
name = new char[strlen(other.name) + 1];
strcpy(name, other.name);
}
else
name = NULL;
}
Stu::~Stu()
{
if (name)
{
delete[] name;
}
name = NULL;
}
int main()
{
Stu stu1("chj");
Stu stu2(stu1);
return 0;
}
四、this指针
1.是什么?(指向调用者自身的指针)
1.this指针是系统自动生成的,不是类的成员(不是类的成员),
2.但是每个类的对象都会有自己的this指针,值为对象本身的首地址
3.当类的普通函数在访问类的普通成员的
时候,该this指针总是指向调用者对象
(在普通成员函数访问类数据成员时,隐式的用this指针;这句话是错的)
参考下面的例程:
//自己调试看看num的值有什么问题
#include <stdio.h>
class Stu
{
public:
int num;
int a;
public:
Stu(int num);
};
Stu::Stu(int num)
{
num = num;
}
int main()
{
Stu obj(10);
return 0;
}
2.定义?
没有定义
3.使用:
1.作用域为类内,类外不可使用
2.引出栗子局部变量的屏蔽作用
#include <stdio.h>
#include <string>
class Stu
{
int num;
public:
Stu(int num);
};
Stu::Stu(int num)
{
num = num;//num前面没有this不会自动调用
//相反这里的num时形参num不是成员num
}
int main()
{
Stu stu1(10);
return 0;
}
//修改
Stu::Stu(int num)
{
this->num = num;
}
3.返回值return this或者是return *this(这里就要用引用去接还是都可以)
#include <stdio.h>
#include <string>
class Stu
{
int num;
int a;
public:
Stu* fun()
{
return this;
}
Stu(int i);
Stu& fun2();
};
Stu& Stu::fun2()
{
return *this;
}
Stu::Stu(int i)
{
a = 1;
num = i;
}
int main()
{
Stu stu1(10);
Stu* p = stu1.fun();
printf("%x %x\n",&stu1,p);
return 0;
}
LAST:question:类不可以向结构体那样初始化啊(属性为私有)
class Stu
{
public:
int num;
int a;
};
int main()
{
Stu stu = {1,2};//error
return 0;
}
1.public:构造函数只能为共有函数不然会报错