C++问题的补充
前言
关于对之前遗留的补充
- malloc 和 new 的区别
- const 和 引用 的深入
- this指针 的深入
一、C++中对象的创建
malloc和new创建对象
//定义一个Pointer类
class Pointer
{
public:
int row;
int col;
Pointer()
{
row = 0;
col = 0;
}
Pointer(int r, int c)
{
row = r;
col = c;
}
~Pointer()
{
cout << "Pointer" << endl;
}
};
malloc不能创建对象,需要配合定位new
使用
//什么是 定位new
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
换句话说就是,现在空间已经有了,不需要定位new像常规new一样去给申请
空间,只需要定位new在已有的空间上调用构造函数构造对象而已。
简而言之,已存在空间,再构造对象。
malloc作用:
- 1、堆区申请空间
- 2、堆区无对象
//定位new,在已有(malloc申请的)空间上,构造对象
int main()
{
Pointer* s = (Pointer*)malloc(sizeof(Pointer));
new(s) Pointer(12, 23);
s->~Pointer();
free(s);
s = NULL;
return 0;
}
new创建对象的的过程:
- 1、调用malloc,从堆区申请空间
- 2、构建对象,调用构造函数
- 3、对象地址空间返回给p
//普通new,先申请空间,再创建对象
int main()
{
Pointer p1(100,200);
Pointer p;
p = new Pointer(10,20);
delete p;
return 0;
}
二、new 和 malloc 的区别
区别 | new | malloc |
---|---|---|
属性 | 关键字 | 库函数 |
参数 | 无需指定内存块大小,编译器实现 | 需要指定大小 |
返回类型 | 对象类型的指针 | void * |
重载 | 支持 | 不支持 |
内存 | 在free store上分配内存 | 在堆区空间分配内存 |
分配失败 | bac_alloc异常 | 返回NULL |
自定义类型 | 可以调用析构与构造 | 不可调用析构和构造 |
效率 | 高 | 低 |
三、C与C++的一个重要区别
C语言:有空间一定能操作
C++: 有空间不一定有对象,有对象一定要有空间
C
int main()
{
char str[10];
int* ip = (int*)str;
*ip = 100;
}
C++:有对象一定要有空间
//有对象一定有空间,即使是空类
class Test
{
};
int main()
{
Test t;
cout << sizeof(t) << endl; //空类大小为1
return 0;
}
空类的大小:
声明类型时也需要占用一些空间
如果没有这个空间,也就不知道该类型的存在。
空类具体占用的空间大小由编译器决定,vs2022中大小为1
编译器自动为其安插1个char。
//有空间可能没对象
int main()
{
CGoods* p = (CGoods*)malloc(sizeof(CGoods));
cout << p->GetPrice() << endl; //结果:-4.31602e+08
}
四、this指针
1. 什么是this指针
例子代码如下:
//一个商品类型
class CGoods
{
private:
char Name[21];
int Amount;
float Price;
float Total_value;
public:
void RegisterGoods(const char[], int, float); //注册商品
void CountTotal(); //总共数量
void GetName(const char[]); //获得名字
int GetAmount(void); //读取商品
float GetPrice(void); //得到价格
float GetTotal_value(void); //总价
};
void CGoods::RegisterGoods(const char name[], int amount, float price)
{
strcpy_s(Name, 21, name);
//strcpy_s(this->Name, 21, name);
Amount = amount;
//this->Amount = amount;
Price = price;
//this->Price = price;
}
void CGoods::GetName(const char name[])
{
strcpy_s(Name, 21, name);
}
int CGoods::GetAmount(void)
{
return Amount;
}
float CGoods::GetPrice(void)
{
return (Price);
}
int main()
{
CGoods c1, c2, c3;
c1.RegisterGoods("C++", 12, 98.99);
c2.RegisterGoods("C++", 23, 15.9);
c3.RegisterGoods("C++", 44, 54.3);
return 0;
}
这里并没有this的存在,那么this指针在哪呢?
首先来看一下C++模型对象的安排
方法一:各对象完全独立的安排内存
上图是系统为c1,c2,c3对象分配了全套的内存,包括安放成员数据的数据区和安放成员函数的代码区。但是区别同一个类所实例化的对象,是由属性(数据成员)的值决定,不同对象的数据成员的内容是不一样的,而行为(操作)是用函数来描述的,这些操作的代码对所有的对象都是一样的。
方法二:数据区私有,代码区公有
在C++中,通过公共代码区节省了大量的空间。
那么对象是如何区分哪个是自己的数据区呢?
this指针就是解决这个问题的。
2. this指针的底层
首先明确几个概念:
- this指针不属于对象的一部分,不会影响sizeof(对象)的结果。
- 只有在类的非静态成员函数中才可以使用this指针,其它任何函数都不可以。
- this的作用域在类成员函数的内部。
当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。也就是说,即使你没有写上this指针,编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含形参,对各成员的访问均通过this进行。
仍然是上一个例子:
//注释为本质
//成员方法的第一个参数添加一个对象类型的this指针。
//成员方法中出现的所有成员属性由this指针指向。
void CGoods::RegisterGoods(const char name[],