类中限定对象的长相
C++构造函数
为什么需要构造函数?
- 构造函数:可以说你所创建对象的骨骼,你的构造函数决定了你可以创建什么样的对象。
- 构造函数更多是用来初始化数据成员
- 不写构造函数:只能创建 不带参数的对象
- 当我们自己写了构造函数,默认的构造函数就不存在了
class Boy {
public:
void print() {
cout << "Im a boy class`s objection" << endl;
}
protected:
string name;
int age;
};
Boy boy;
boy.print();
Boy bboy = { "boy",19 };// 错!!!
构造函数长什么样子
#include"iostream"
#include"string"
using namespace std;
class MM {
public:
MM(){};// 默认构造函数
MM(string nname , int aage) {
name = nname;
age = aage;
cout << "Im consttructorfun" << endl;
}
void print()
{
cout << name << '\t' << age << endl;
}
protected:
private:
string name;
int age;
};
int main()
{
MM mm;//调用默认构造函数
MM girl("Lisa", 18);// 调用自己写构造函数
while(1);
return 0;
}
初始化参数列表 : 只有构造函数有<这个必须学会,继承 会用到>
好处:避免形参名和数据成员名相同的导致问题
MM(string nname="", int aage = 18) :name(nname), age(aage) {
name = nname;
age = aage;
cout << "Im consttructorfun" << endl;
}
构造函数缺省 (MM(string nname="", int aage = 18) :name(nname), age(aage))可以让我们写出 已知参数不完整对象
- 人话:这种写法可以设置默认参数
#include"iostream"
#include"string"
using namespace std;
class Boy {
public:
void print() {
cout << "Im a boy class`s objection" << endl;
}
protected:
string name;
int age;
};
class MM {
public:
//MM() {};// 默认构造函数
MM(string nname="", int aage=88 /*默认参数*/) :name(nname), age(aage) {
name = nname;
age = aage;
cout << "Im consttructorfun" << endl;
}
void print()
{
cout<< name << '\t' << age << endl;
}
protected:
private:
string name;
int age;
};
int main()
{
Boy boy;
boy.print();
// bboy = { "boy",19 };wrong
MM mm;//调用默认构造函数
mm.print();
MM girl("Lisa", 18);// 调用自己写构造函数
girl.print();
MM mmy = {"KK"}; // 年龄默认88
mmy.print();
while(1);
return 0;
}
运行结果:
析构函数
- 析构函数长什么样子?
- 无返回值
- 无参数
- 函数名: ~类名
- 不写的话会存在默认的析构函数
- 析构函数不需要自己 调用,对象死亡的之前会调用析构函数
~MM();//析构函数
-
为什么需要析构函数(什么时候需要自己手动写析构函数)
- 当类中的数据成员是指针,并且动态申请内存就需要手写析构
- 析构函数用来释放数据成员申请动态内存
#include"iostream"
#include"string"
using namespace std;
class MM {
public:
MM(string nname = "", int aage = 18) :name(nname), age(aage) {
int *p = new int;
name = nname; age = aage;
}
void print() {
cout << name << '\t' << age << endl;
cout << num << endl;
}
~MM() {
cout << "我是析构函数" << endl;
}//析构函数
protected:
private:
string name;
int age;
int *num;
};
int main()
{
MM m;
m.print();
m.~MM();// 手动调用
// 我的为什么不自己调用?
MM mm = { "kk" };
mm.print();
while (1);
return 0;
}
拷贝构造函数
-
什么时候调用拷贝构造?
- 当通过一个对象去创建出来另一个新的对象时候需要调用拷贝
-
拷贝构造函数也是构造函数,长相和构造函数一样的,只是参数是固定
- 拷贝构造函数唯一的参数是对对象引用
-
不写拷贝构造函数,也存在一个默认的拷贝构造函数
-
拷贝构造函数作用: 通过一个对象去初始化另一个对象
<会继承上一个对象的参数>
如: MM girl = mm;
girl.print();
#include"iostream"
#include"string"
using namespace std;
class MM {
public:
MM(string nname = "", int aage = 18) :name(nname), age(aage) {
int *p = new int;
name = nname; age = aage;
}
void print() {
cout << name << '\t' << age << endl;
cout << num << endl;
}
MM(MM& mm)
{
name = mm.name;
age = mm.age;
cout << "我是拷贝构造函数" << endl;
}
~MM() {
cout << "我是析构函数" << endl;
}//析构函数
protected:
private:
string name;
int age;
int *num;
};
int main()
{
MM m;
m.print();
m.~MM();// 手动调用
// 我的为什么不自己调用?
MM mm = { "kk" };
mm.print();
MM girl = mm;
girl.print();
girl = { "girl",19 };
girl.print();
while (1);
return 0;
}
//显示调用调用
MM girl(mm); //通过一个对象创建另一个对象
girl.print();
//隐式调用
MM girl2 = mm; //拷贝构造
girl2.print();
深浅拷贝
-
浅拷贝: 默认的拷贝构造叫做浅拷贝
-
深拷贝: 拷贝构造函数中做了new内存操作,并且做拷贝赋值的操作
#include"iostream"
#include"string"
using namespace std;
class MM {
public:
//MM() = default;// 想要保留默认够赞函数 并写出不带参 对象
MM(const char* nname="gg",int aage=18) :age(age) {// 用缺省写法时 上面代码 可以省略
age = aage;
name = new char[strlen(nname) + 1];
strcpy_s(name, strlen(nname) + 1, nname);
cout << "Im construction fun" << endl;
}
MM(int aage) :name(name) {
// 为什么写不出
age = aage;
cout << "Im construction fun2" << endl;
}
~MM() {
cout << "我是死神析构函数" << endl;
delete name;
}
void print()
{
cout << name << '\t' <<age << endl;
}
protected:
private:
char* name;
int age;
};
int main()
{
MM mm;
mm.print();//默认名 gg 默认年龄18
MM girl = {"JJ"};
girl.print();//默认年龄 18
MM boy("HH", 19);
boy.print();
return 0;
}
- 为什么做不到 名字 默认 年龄已知?
- 拷贝构造什么时候需要加const修饰参数?
- 当存在匿名对象赋值操作的时候,必须要const修饰
匿名对象 临时变量 《这时需要 构造中写 const MM mm》
- 当存在匿名对象赋值操作的时候,必须要const修饰
构造和析构顺序问题
- 普通对象,构造顺序和析构顺序是相反
- 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;
}
Homework:
这个问题我一直没解决掉!!!!!!!!!!
#include"iostream"
#include"cstring"
using namespace std;
class myString {
public:
myString() {};//等效 myString()=default;
myString(const char* Str ) {//传常量用
str = new char[strlen(str)+1];
strcpy_s(str, strlen(str) + 1, Str);
}
// 因为有 指针申请,所以一定是深拷贝
myString(const myString& object)
{
str = new char[strlen(object.str) + 1];
strcpy_s(str, strlen(object.str) + 1, object.str);
}
char* c_str() {
return str;
}
char* data(){
return str;
}
myString append(const myString& object) {
myString temp;
int lon = 2 * strlen(temp.str);
strcat_s(temp.str,lon, str);
strcat_s(temp.str, lon, object.str);
return temp;
}
int compare(myString& object)// 0 1 -1
{
return strcmp(object.str, str);
}
~myString() {
delete str;
str = nullptr;
cout << "析构函数1" << endl;
}
private:
protected:
char* str;
};
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++中结构体中 用了构造函数就是 class
- C++ 中
结构体 默认public
class 中默认private - 对构造缺省不够了,急需加深理解,理清思路
- 析构调用 有问题,也许编译器没调好
浅拷贝:通过对象创建对象存在 西沟问题(多次释放)
深拷贝: 在 默认拷贝中 申请内存strcpy(name,name…)存放 避免了多次释放
<< 这次作业写得非常艰难《昨天晚上2+今天上午》,博客也是。因为拿课余时间写加上 思路不清晰花了大量时间效果也不佳!
应该要做出改变。