动态对象创建
努力的意义,不是让你取得多大的成就,而是让你在平凡的日子里,活得比原来的那个自己更好一点。
1、和malloc calloc realloc比较
当我们创建数组的时候,总是需要提前预定数组的长度,然后编译器分配预定长度 的数组空间,在使用数组的时,会有这样的问题,数组也许空间太大了,浪费空 间,也许空间不足,所以对于数组来讲,如果能根据需要来分配空间大小再好不 过。 所以动态的意思意味着不确定性。 为了解决这个普遍的编程问题,在运行中 可以创建和销毁对象是最基本的要求。当然c早就提供了动态内存分配(dynamic memoryallocation),函数malloc和free可以在运行时从堆中分配存储单元。 然 而这些函数在c++中不能很好的运行,因为它不能帮我们完成对象的初始化工作。
1.1、malloc返回一个void指针,c++不允许将void赋值给其他任何指针,必须强转。
1.2、malloc可能申请内存失败,所以必须判断返回值来确保内存分配成功。
1.3、malloc 不会调用构造函数。free 不会调用析构函数(重要的)
当创建一个c++对象时会发生两件事:
- 为对象分配内存
- 调用构造函数来初始化那块内存 第一步我们能保证实现,需要我们确保第二 步一定能发生。c++强迫我们这么做是因为使用未初始化的对象是程序出错的 一个重要原因。4.3.9.2C动态分配内存方法 为了在运行时动态分配内存,c 在他的标准库中提供了一些函数,malloc以及它的变种calloc和realloc,释放内 存的free,这些函数是有效的、但是原始的,需要程序员理解和小心使用。为 了使用c的动态内存分配函数在堆上创建一个类的实例,我们必须这样做:
lass Person
{
public:
Person()
{
mAge = 20;
pName = (char*)malloc(strlen("john")+1);
strcpy(pName, "john");
}
void Init()
{
mAge = 20;
pName = (char*)malloc(strlen("john")+1);
strcpy(pName, "john");
}
void Clean()
{
if (pName != NULL)
{
free(pName);
}
}
public:
int mAge;
char* pName;
};
int main()
{
//分 配 内 存
Person* person = (Person*)malloc(sizeof(Person));
if(person == NULL)
{
return 0;
}
// 调 用 初 始 化 函 数
person->Init(); // 清 理 对 象
person->Clean(); // 释 放 person 对 象
free(person);
return EXIT_SUCCESS;
}
问题:
1)程序员必须确定对象的长度。
2)malloc返回一个void指 针 , c++ 不允许将 void 赋值给其他任何指针,必须强转。
3)malloc可能申请内存失败,所以必须判 断返回值来确保内存分配成功。
4)用户在使用对象之前必须记住对他初始化,构 造函数不能显示调用初始化(构造函数是由编译器调用),用户有可能忘记调用初始 化函数。
c 的动态内存分配函数太复杂,容易令人混淆,是不可接受的,c++中我们推荐使用 运算符new和delete。
2、new 给基本类型申请空间
C ++中解决动态内存分配的方案是把创建一个对象所需要的操作都结合在一个称为new的运算符里。当用new创建一个对象时,它就在堆里为对象分配内存并调用构 造函数完成初始化。
Person* person = new Person;
相当于:
Person* person = (Person*)malloc(sizeof(Person));
if(person == NULL)
{
return 0;
}
person->Init(); //构造函数
New操作符能确定在调用构造函数初始化之前内存分配是成功的,所有不用显式 确定调用是否成功。 现在我们发现在堆里创建对象的过程变得简单了,只需要一个简单的表达式,它带有内置的长度计算、类型转换和安全检查。这样在堆创建一 个对象和在栈里创建对象一样简单。
void test01()
{
//基本类型
int *p = NULL;
//p = (int *)calloc(1,sizeof(int));
//p = new int(100);// *p = 100
p = new int;
*p = 100;
cout<<"*p = "<<*p<<endl;//100
//释放 free(p)
delete p;
}
3、new 申请 基本类型数组空间(案例)
注意:
new 没有加[] delete释放的时候 就不加[]
new 加[] delete释放的时候 就加[]
4、new delete 给类对象申请空间
无参
void test04()
{
data *p = new data;
delete p;
}
有参
void test05()
{
data *p = new data{"lucy",18};
p->showdata();
delete p;
}
对象数组
本质是数组 只是数组的每个元素是类的对象
void test06()
{
//对象数组 ob是数组每个元素是data类型的对象
//定义对象数组的时候 系统会自动给 数组中的每个元素 调用构造函数
//调用无参构造函数
data ob[5];
}
运行结果:
如果想让对象数组中的元素调用有参构造 必须人为使用 有参构造初始化。
void test07()
{
//对象数组 arr1是数组 每个元素是Person类型的对象
//定义对象数组的时候 系统会自动给 数组中的每个元素 调用构造函数
//人为 为元素 调用有参构造
//初始化部分 调用有参构造 为初始化部分自动调用默认构造(无参构造)
data arr1[5]={ data("lucy",18), data("bob",20)};
//arr1[0] 第0个元素 就是Person的对象
arr1[0].showdata();
arr1[1].showdata();
}
运行结果:
用new delete申请 对象数组
尽量不要用delete释放void *
注意:没有析构?为什么?
delete发现p1指向的类型 为void 无法从void中寻找响应析构函数