首页IT科技c++入门知识(C++学习笔记 (2))

c++入门知识(C++学习笔记 (2))

时间2025-08-05 02:50:12分类IT科技浏览3921
导读:C++问题的补充 前言...

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[], int amount, float price) //void CGoods::RegisterGoods(CGoods *this,const, 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; } int main() { c1.RegisterGoods("C++", 12, 98.99); //对象 + . 调用成员方法的本质 //逻辑上面向对象      ,实际上是面向过程 //RegisterGoods(&c1, "C++", 12, 98.99); }

这样就不难理解         ,当通过 对象 + . 调用成员方法时                    ,会将对象的地址作为第一个参数传递给成员方法         ,这也是一个对象数据区的唯一标识             。得到该地址以后      ,调用成员函数中如果遇到成员属性                    ,就给每个属性前面加上this                    。

3.this指针 的类型

this指针的类型为 : 类型名 * const this

      。

但是在VS2022中发现并没有这个const            ,不知道是什么情况

4. C++类成员函数默认调用方式 与 c语言调用方式的区别

C++默认调用(C++成员函数的this指针)

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); //C++的调用约定 lea ecx , [c1] c1.CountTotal(); return 0; }

对象 . 调用成员方法   ,逻辑上是面向对象                    ,物理上还是面向过程               ,会将对象地址传递给成员函数的this指针         。对象的地址传递时候,直接进行 lea ecx, [c1]                    。到达成员函数内部时                 ,使用mov指令                   ,将ecx的值传递给this指针         。

c语言调用方式(thiscall调用)

在成员函数前面加上__cdecl    ,说明是C的调用约定             ,我们可以将c1的地址传递给eax                    ,通过push指令入栈eax      ,直接传递给形参      。

//通过使用__cdecl改写 thiscall //void __cdecl CGoods::RegisterGoods(const char name[], int amount, float price);

5   、this 与 常对象

常对象只能调用常方法         ,普通对象能调用普通方法和常方法                    。

例子:

//main函数中                    ,哪些语句能编译通过 class CGoods //设计类型         ,不是定义类型 { private: char Name[21]; int Amount; float Price; float Total_value; public: CGoods(char name[], int amount, float price, float total_value) { strcpy_s(Name, name); Amount = amount; Price = price; Total_value = total_value; } void RegisterGoods(const char[], int, float); float GetPrice(void) { return Price; } float GetTotal_value(void) const { return Total_value; } }; int main() { CGoods c1 = { "C++",12,23.0,23.0 }; const CGoods c2 = { "java",12,23 }; c1.GetPrice(); //right:普通对象调用普通方法可以通过this指针修改成员函数的值 c2.GetPrice(); //error:常对象不能调用普通方法            。常对象调用普通方法时      ,成员属性有修改的风险                    ,所以报错   。 c1.GetTotal_value(); //right:普通对象既可以调用普通方法又可以调用常方法 c2.GetTotal_value(); //right:常对象只能调用常方法 }

我们知道了this指针的类型是 对象名 *const this                    。那么对象加 const 也就是const 对象名 *const this类型            ,为了给this指针所指向的对象限定   ,也就是不允许修改对象中的成员属性                    ,那么任何对成员属性进行修改的行为都是错误的               。

四                    、const 回顾

int main() { const int a = 10; int b = 20; int* p1 = &a; //error:可以通过p1改变a const int* p2 = &a; //right:p2所指向的值不能修改 int* const p3 = &a; //error:可以通过p3改变a               ,但不能改变p3的指向 const int* const p4 = &a; //right:能力收缩 return 0; }

五               、构造函数和析构函数

1.构造函数和析构函数的用法

class Pointer { public: int row; int col; //构造函数: //1、函数名与类名相同 //2                 、无返回值 //3                   、对象实例化时,编译器自动调用 //4   、可以重载 Pointer() //无参构造函数                 ,缺省构造 { row = 0; col = 0; } Pointer(int r, int c) //构造函数重载 { row = r; col = c; } ~Pointer() //析构函数 { cout << "Pointer" << endl; } //析构函数: //1             、~ + 类名 //2                    、析构函数无函数返回值类型 //3      、一个类只能一个也只能有一个析构函数 //4         、对象注销时                   ,系统会自动调用 //5                    、如果没有给出析构函数   ,系统会给出默认析构函数 }; int main() { Pointer c1 = { 12,23 }; Pointer c2; //right:调用缺省构造函数 //Pointer c2(); //error:没有参数不需要带括号 Pointer c3(10, 20); //right:调用带参数构造函数 //不能通过对象手动调用构造函数 //c2.Pointer(10,20); //error //有空间不一定有对象             ,得要对象调用构造函数来构建对象                    ,才有空间 //有对象一定有空间 return 0; }

2.构造函数和构造函数的执行顺序

留给后面

class Object { private: int val; public: Object(int x) { val = x; cout << "create :" << val << endl; } }; Object o1(1); int main() { Object o2(2); } Object o3(3);

已解决:程序执行顺序

总结

待解决的问题:

const 和 引用 的深入 [程序执行顺序] 类中的默认成员方法

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
迷你无线路由器说明书(plink 150m迷你型无线路由器出故障该怎么办)