构造和析构的概念
- 创建对象时,对象进行初始化的工作,就是构造
- 销毁对象时,对对象进行清理工作,就是析构
创建对象和释放对象时,构造函数和析构函数自动调用,不需要人为调用
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
class Person
{
public:
// 构造函数 函数名和类名一致 没有返回值 不能写void 可以有参数 可以发生函数重载
Person(int age, string name)
{
m_age = age;
m_name = name;
}
// 析构函数 函数名:类名前加~ 没有返回值 不可以有参数 不能发生函数重载
~Person()
{
cout <<"~~~~" <<endl;
}
int m_age;
string m_name;
};
void test01()
{
Person p1(10, "lucy"); // 构造函数是在实例化对象时会创建,就是在内存开辟空间时会被调用
// 销毁之前,自动调用析构函数
}
int main()
{
test01();
return 0;
}
构造函数的分类及调用
- 按参数类型:分为无参构造函数和有参构造函数
- 按类型分类:普通构造函数和拷贝构造函数(复制构造函数)
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
class Person
{
public:
// 构造函数 函数名和类名一致 没有返回值 不能写void 可以有参数 可以发生函数重载
Person(int age, string name)
{
m_age = age;
m_name = name;
cout <<"can" <<endl;
}
Person(){
cout <<"wu" <<endl;
}
// 析构函数 函数名:类名前加~ 没有返回值 不可以有参数 不能发生函数重载
~Person()
{
cout <<"~~~~" <<endl;
}
// 拷贝构造的调用时机:旧对象初始化新对象
Person(const Person &p) // 这里的&是引用 常量引用
{
// 拷贝构造做了简单的值拷贝
m_age = p.m_age;
m_name = p.m_name;
cout <<"copy.." <<endl;
}
int m_age;
string m_name;
};
void test01()
{
Person p1(10, "lucy"); // 构造函数是在实例化对象时会创建,就是在内存开辟空间时会被调用
// 销毁之前,自动调用析构函数
Person p2; // 调用无参构造的时候,不能使用括号
Person p3(p1); // 调用了拷贝构造
}
int main()
{
test01();
return 0;
}
构造函数的深浅拷贝
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
class Person
{
public:
Person(int age, char *str)
{
mAge = age;
name = (char *)malloc(strlen(str)+1);
strcpy(name, str);
cout <<"cacaca" <<endl;
}
void show()
{
cout << mAge <<" " << name <<endl;
}
Person(const Person &p) // 深拷贝 浅拷贝 编译器优化?
{
mAge = p.mAge;
name = (char *)malloc(strlen(p.name)+1);
strcpy(name, p.name);
}
~Person()
{
cout <<"~~~~" <<endl;
if(name != NULL)
{
free(name);
name = NULL;
}
}
int mAge;
char *name;
};
void test01()
{
Person p(10,"bob");
p.show();
Person p1(p); // 调用拷贝构造函数
p1.show();
}
int main()
{
test01();
return 0;
}
类对象作为另外一个类的成员
- 类中有多个对象时,构造的顺序是先构造里面的对象,再构造外面的对象
- 类中有多个对象时,析构的顺序是先析构外面的对象,再析构里面的对象
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
class Game
{
public:
Game(){}
Game(string gameA)
{
game = gameA;
}
string game;
};
class Phone
{
public:
Phone(){}
Phone(string phoneA)
{
phone = phoneA;
}
string phone;
};
class Person
{
public:
// 初始化
/*
Person(string perName, string pho, string gam)
{
per_name = perName;
Game.game = gam;
Phone.phone = pho;
}
*/
Person(string perName, string pho, string gam):per_name(perName),phone(pho),game(gam)
{
cout <<" person... " <<endl;
}
void show()
{
cout << per_name << " "<< phone.phone << " " << game.game << endl;
}
string per_name;
Game game;
Phone phone;
};
void test01()
{
Person p("aa","xiaomi","llkan");
p.show();
}
int main()
{
test01();
return 0;
}
malloc相关的问题
1、程序员必须确定对象的长度
2、malloc返回一个void指针,c++不允许将void赋值给其他任何指针,必须强转
3、malloc可能申请内存失败,所以必须判断返回值来确保内存分配成功
4、用户在使用对象之前,必须记住对它初始化。构造函数不能显示调用初始化(构造函数是由编译器调用),用户有可能忘记调用初始化函数
c的动态内存分配函数太复杂,容易令人混淆,是不可能接受的。
c++中我们推荐使用运算符 new 和 delete
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
Person()
{
cout<<"wu can"<<endl;
}
Person(int a1)
{
a = a1;
cout<<"you can"<<endl;
}
~Person()
{
cout<<"xi gou..."<<endl;
}
int a;
};
void test01()
{
int *p = new int; // 申请一块内存 sizeof(int)大小 并且对这块内存进行初始化
cout <<*p <<endl;
*p = 100;
cout <<*p << endl; // 100
delete p; // 释放申请的空间
// 申请一个对象
Person *p1 = new Person; // sizeof(Person) 这里会调用无参构造函数
delete p1; // 会调用析构函数
Person *p22 = new Person(10); // new时调用有参构造
delete p22;
Person *p222 = new Person[3]; // new对象的数组时,不是调用有参构造,而是调用无参构造
delete []p222; // 得加[] ; delete p222 ; 这个是删除首元素地址的意思
// 申请一个数组
int *p2 = new int[10]; // new一个数组时,返回的是该数组的首元素的地址
for(int i=0; i<10; i++)
{
p2[i] = i+100;
}
for (int i=0; i<10; i++)
{
cout << p2[i] << " "; // 100 101 102 103 104 105 106 107 108 109
}
cout << endl;
delete []p2; // 得加[] ; delete p ; 这个是删除首元素地址的意思
}
int main()
{
test01();
return 0;
}