IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 一文详解C++动态对象创建 -> 正文阅读

[C++知识库]一文详解C++动态对象创建

?当我们创建数组的时候,总是需要提前预定数组的长度,然后编译器分配预定长度的数组空间,在使用数组的时候,可能数组的空间不太大,浪费空间,也许空间太大了,浪费空间,也许空间不足,所以对于数组来说,如果能够根据需要分配空间大小再好不过。

?C语言中很好的提供了动态分配内存,malloc和free可以在运行时从堆中分配存储单元

一、C语言创建和销毁堆区空间出现的问题

  • 程序员必须确定对象的长度
  • malloc返回一个void* 指针,C++不允许将void*赋值给其他指针,必须进行强制转换
  • malloc可能申请内存失败,所以必须判断返回值来确保内存分配成功
  • 用户在使用对象之前必须记住对他初始化,构造函数不能显示调用初始化(构造函数都是由编译器进行调用的),用户有可能忘记调用初始化函数

对于最后一点,案例如下:

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {

public:
	// explicit 关键字只能放在构造函数前面 构造函数只有一个参数或者其他参数有默认值时
	// 防止编译器优化 Maker m = 10; 这种格式
	Maker()
	{
		
		cout << "调用构造函数" << endl;
	}

	~Maker()
	{
		cout << "调用法国析构函数" << endl;
	}

private:
	int id;

};


void test01()
{
	// 使用C语言方式申请堆区空间  不会调用构造函数 对象释放也不会调用析构函数
	Maker* m = (Maker*)malloc(sizeof(Maker));
    free(m);
}

int main()
{
	//Maker m = 1;//err
	return EXIT_SUCCESS;
}

二、C++创建和销毁堆区空间

C++解决动态内存分配的方案是把创建一个对象所需要的操作都结合在一个new的运算符中,当使用New创建一个对象时,它就在堆中为对象分配内存并且调用构造函数完成初始化

Person* person = new Person;

相当于:
Person* person = (Person*)malloc(sizeof(Person));

if(person == NULL)
{
    return 0;
}

person->init();


案例代码:创建一个无参构造对象

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {

public:
	// explicit 关键字只能放在构造函数前面 构造函数只有一个参数或者其他参数有默认值时
	// 防止编译器优化 Maker m = 10; 这种格式
	Maker()
	{
		cout << "调用构造函数" << endl;
	}

	~Maker()
	{
		cout << "调用析构函数" << endl;
	}

private:
	int id;

};

void test02()
{
	// 用New方式申请堆区空间  会调用类的构造函数
	Maker* m = new Maker;// 这种方式调用的是无参构造函数
	delete m;
    m = NULL;
}


void test01()
{
	// 使用C语言方式申请堆区空间  不会调用构造函数 对象释放也不会调用析构函数
	Maker* m = (Maker*)malloc(sizeof(Maker));
	free(m);
}

int main()
{
	//Maker m = 1;//err
	test02();
	return EXIT_SUCCESS;
}

案例代码:创建一个有参数构造对象

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {

public:
	// explicit 关键字只能放在构造函数前面 构造函数只有一个参数或者其他参数有默认值时
	// 防止编译器优化 Maker m = 10; 这种格式
	Maker(int a)
	{
		cout << "调用构造函数" << endl;
		id = a;
	}

	~Maker()
	{
		cout << "调用析构函数" << endl;
	}

private:
	int id;

};

void test02()
{
	// 用New方式申请堆区空间  会调用类的构造函数
	Maker* m = new Maker(1);
	delete m;
}


void test01()
{
	// 使用C语言方式申请堆区空间  不会调用构造函数 对象释放也不会调用析构函数
	Maker* m = (Maker*)malloc(sizeof(Maker));
	free(m);
}

int main()
{
	//Maker m = 1;//err
	test02();
	return EXIT_SUCCESS;
}

总结:

  • 为什么要有新的方法申请和释放堆区空间?
    • 因为C语言的方式不会调用构造和析构函数
  • C++中申请堆区空间和释放堆区空间用什么关键字
    • 申请堆区空间使用new,释放堆区空间使用delete

三、new和delete用于申请基本类型的数组

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

// new 创建基础类型的数组
void test01()
{
	// 申请基础数据类型的数组
	int* pInt = new int[10]{1,2,3,4,5,6,7,8,9,10};
	for (int i = 0; i < 10; i++)
	{
		//pInt[i] = i + 1;  这样写也可以
		*(pInt + i) = i + 1;
	}

	for (int i = 0; i < 10; i++)
	{
		cout << pInt[i] << " ";
	}

	cout << endl;


	char* pChar = new char[64];
	memset(pChar,0,sizeof(char) * 64);
	strcpy(pChar,"小花");
	cout << pChar << endl;

	// 释放内存空间
	delete[] pInt;
	delete[] pChar;
}

int main()
{
	//Maker m = 1;//err
	test01();
	return EXIT_SUCCESS;
}

四、new创建对象数组

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {
public:
	Maker()
	{
		cout << "构造函数" << endl;
	}

	~Maker()
	{
		cout << "析构函数" << endl;
	}
};

// 创建对象类型的数组
void test02()
{
	Maker* ms = new Maker[2];// 调用无参构造  申请两个对象

	delete[] ms;
}

int main()
{
	//Maker m = 1;//err
	test02();
	return EXIT_SUCCESS;
}

五、delete void * 可能会出错,不会调用对象的析构函数

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {
public:
	Maker()
	{
		cout << "构造函数" << endl;
	}

	~Maker()
	{
		cout << "析构函数" << endl;
	}
};

// 创建对象类型的数组
void test02()
{
	Maker* ms = new Maker[2];// 调用无参构造  申请两个对象

	delete[] ms;
}

// delete void* 可能会出错  不会调用对象的析构函数
void test03()
{
	void* m = new Maker;// 无参构造申请一个对象
	// 如果使用void * 来接new的对象  那么delte时不会调用析构函数
	delete m;
}

int main()
{
	//Maker m = 1;//err
	test03();
	return EXIT_SUCCESS;
}

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {
public:
	Maker()
	{
		cout << "构造函数" << endl;
	}

	~Maker()
	{
		cout << "析构函数" << endl;
	}
};


// delete void* 可能会出错  不会调用对象的析构函数
void test03()
{
	void* m = new Maker;// 无参构造申请一个对象
	// 如果使用void * 来接new的对象  那么delte时不会调用析构函数

	// 在编译阶段  那么编译器就确定好了函数的调用地址
	// C++编译器不认识void* 不知道void* 指向哪一个函数  所以会调用析构函数
	// 这种编译方式叫做静态联编
	delete m;
}

int main()
{
	//Maker m = 1;//err
	test03();
	return EXIT_SUCCESS;
}

六、C和C++的申请和释放堆区空间不要混用

错误写法:

void test04()
{
	Maker *m = new Maker;//c++

	free(m);//c
	
}

c++和C的共同和区别之处:

共同:都是申请堆区空间和释放堆区空间

区别:C++会调用构造和析构函数

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-21 00:08:17  更:2022-09-21 00:10:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 15:34:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码