这一篇我将对C++类与对象进行收尾 1.友元 友元提供了⼀种突破类访问限定符封装的⽅式,友元分为:友元函数和友元类,在函数声明或者类 声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯。 2.匿名对象 用 类型(实参) 定义出来的对象叫做匿名对象,相⽐之前我们定义的 类型 对象名(实参) 定义出来的 叫有名对象 (假设有A类,前者就是A(1),后者则是a1(1)) 匿名对象生命周期只在当前一行 (如前面讲的 隐式类型转换,省略了构造临时对象和拷贝构造,直接优化为构造 ) 如何优化C++标准并没有严格规定,各个编译器会根据情况自行处理。 同样,我们对比一下优化前后 说明:图中的 NRVO 是 命名返回值优化 (C++标准并未说明NRVO可优化,只是编译器的优化) 左图是未优化的时候,f2内构造了一个A类,然后拷贝构造了临时对象,A类销毁 所以尽量避免此写法 C++类与对象结束,接下将会将内存管理,谢谢大家,请多多点赞支持!
我们也可以对部分成员进行初始化,就算我们不进行初始化,编译器自动进行的; 编译器对初始化列表的执行顺序不会按照我们写的顺序,而是按照private里面的成员变量声明的顺序,这个通过调试是可以看到的; (4) 优化之后省去了拷贝的过程和临时变量的创建,直接执行的就是构造函数,我们透过这个打印结果是可以看出来的: (4)对于这个隐式类型转换,我们是可以避免的,就是我们可以使用一些手段不允许编译器进行上面的隐式类型转换 4.匿名对象 (1)匿名对象,与之对应的就是普通的对象,126行就是一个普通的对象,127行就是定义了一个匿名的对象; (2)匿名对象一般是针对什么场景进行使用的呢? 匿名对象一般是针对的只会使用一次的对象进行使用的; (3)匿名对象和普通对象的区别:普通对象的生命周期在当前的局部域,匿名对象的生命周期是在这一行,在这里的匿名对象的生命周期就在127行,我们这里可以写一行析构函数打印输出查看这个匿名对象的创建和销毁 ; (4)匿名对象怎么用:假如有一个solution函数,我们使用普通的对象,先创建bb2在使用bb2这个对象调用这个solution函数,这里显得很费劲,我们创建这个对象就是为了调用这个solution
总结 4. 参考 1. 概述 在前面两篇文章《面向对象编程(C++篇2)——构造》和《面向对象编程(C++篇3)——析构》中,我们论述了C++面向对象中一个比较好的实现,在构造函数中申请动态内存,在析构函数中进行释放。 通过这种方式,我们可以实现类对象如何内置数据类型对象一样,自动实现对象的生命周期管理。 对此,现代C++给出地解决方案就是RAII。 在现代C++中,动态内存推荐使用智能指针类型(shared_ptr、unique_ptr、weak_ptr)来管理动态内存对象。 当然,这也是C++"零成本抽象(zero overhead abstraction)"的设计哲学的体现。 4. 参考 C++中的RAII介绍 RAII:如何编写没有内存泄漏的代码 with C++
在 C++ 编程世界中,类与对象是面向对象程序设计(OOP)的核心基石。从简单的数据封装到复杂的继承多态,类与对象机制为我们提供了模块化、可复用、易维护的代码组织方式。 成员函数声明; // 方法 }; // 成员函数实现(类外) 返回类型 类名::成员函数名(参数列表) { // 函数体 } 4.2.2 类成员的访问控制 C+ // 测试默认构造函数 Book b1; b1.showInfo(); cout << endl; // 测试带参数构造函数 Book b2("C+ = b3; // 调用复制构造函数 cout << "b4是b3的复制:" << endl; b4.showInfo(); cout << endl; // 深度主题:位域、类型转换、对象传递方式等高级特性,帮助理解底层机制。 掌握类与对象是学好 C++ 的关键,它们为后续学习继承、多态、模板等高级特性奠定了基础。
C++先声明类类型,然后再定义对象 在C++中,声明了类类型后,定义对象有两种形式 1、class 类名 对象名 //把class和Student合起来作为一个类名,用来定义对象 class Student stu1,stu2; 2、类名 对象名 //直接用类名定义对象 Student stu1,stu2; 这两种方法是等效的,第1种方法是从C语言继承下来的,第2种方法是C++的特色,第2种方法更为简捷方便 C++声明类类型的同时定义对象 在定义Student类的同时,定义了两个Student类的对象。 C++在定义一个对象时,编译系统会为这个对象分配存储空间,以存放对象中的成员,在小型程序中或所声明的类只用于本程序时,也可以用声明类类型的同时定义对象。 C++定义对象 | 对象举例 更多案例可以go公众号:C语言入门到精通
Markdown 画图工具 Processon 1,关于对象 从这篇博客开始真正介绍C++对象模型,前边BB了那么多没用的,终于开始了C++对模型的分析。 关于C++对象模型的介绍,我将根据《深度探索C++对象模型》这本书,其书中的每一章,对应一篇博客,博客内容为自己对这本书的理解和补充吧。 pd.init(&pd); } 1.2 class 需要指出的是,C++类的非static的成员函数都有一个隐式的参数,即this(class object *const this)指针(对象的首地址) C++在内存布局以及存取时间上主要的额外负担是虚函数(即链接时的多态)和虚继承(即多次出现在继承体系中的父类,在子类对象中有一个单一共享的实例,其最典型的是菱形继承) 另外,需要指出的是,C++中class class point2d的对象对应的内存布局 通过对比point和point2d的对象内存布局,可知,如果父类中定义了虚函数,并且在子类中进行了重写,则在子类的对象模型中,用子类重写的函数的地址将父类的虚函数地址替换掉
前言 大家好吖,欢迎来到 YY 滴 C++系列 ,热烈欢迎! 【 '类与对象'-三部曲】的大纲主要内容如下: 如标题所示,本章是【 '类与对象'-三部曲】三章中的第二章节——类章节,主要内容如下: 一.类 C++兼容C,C语言中的结构体strcut也算是一种类,是 ,如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义,编译器将不再生成。 Stack d1(); // 不可以这样写,会跟函数声明有点冲突,编译器不好识别 Stack d2; //调用时可以用d2,使用下方的构造函数 Stack(int capacity = 4) 二.默认拷贝构造(浅拷贝)的缺陷: 浅拷贝的缺陷:(默认拷贝构造运用 引用 防止死递归的后遗症) 4.运算符重载函数(第四个) 运算符重载: 参数类型:const T& (传递引用可以提高传参效率
作为C++的核心单元,对象模型在编译器眼中是如何实现的?本文从几个基本理论模型出发,剖析实际。 深度探索C++对象模型 ---- 简单对象模型 对象存放若干slots,由slot指向实际成员。 一个古老的实现方法是,在每一个派生类对象中存放一个虚基类指针而非传统对象模型中的基类对象本身,对虚基类的访问通过指针间接实现,以此实现共享。 为语法苦恼的应该是C++编译器作者,而不是程序员。 一般而言,为了避免上述困扰,推荐的方法是面向接口(类型)编程,即一个没有data member的虚基类。 ---- C++对象模型 上述模型的Extension部分其实已经涵盖了部分对象模型的静态结构,而对象模型的生成与维护则更多见原书中的一系列章节。 Bjarne Stroustrup设计的C++对象模型从简单对象模型派生而来,对内存空间和存取时间做了优化。
最近在公司弄游戏开发,C++基础也不是特别好,所以就打算继续开始学习C++。 既然从头学习C++,就打算写一个系列教程。C++学习之路。 我是在边学习C++,边学习cocos2dx 3.X,白天时间不是很多, 先把C++系列写完再写coco2dx的教程。 希望对大家有帮助。 (可能基础知识不是很详细,对没有其他语言基础的人来说不是很友好,请见谅) 每个实体都可以看成一个对象。在C++中,对象的类型被称为类。 类代表了某一批对象的共性和特征。 类是对象的抽象,而对象是类的具体实现。 在C++中要使用一个类,首先要定义一个类。 定义类 定义类和声明结构体的结构是相似的。 对象成员的引用 程序中访问对象成员有以下三种方法: 1、通过对象名和成员访问运算符”.”来访问 2、通过指向对象的指针来访问 3、通过引用来访问 Student stu;
C++之类和对象(中)后续 本节目标 1. 总结 本节目标 本篇文章衔接类和对象(中),将剩余的部分进行讲解: 1.日期类实现 2.输入流、输出流 3.const成员函数 4.取地址及const取地址操作符重载 1. 在这里进行一下const和static的区分: 对于C/C++来说: const就是只读的意思,只在声明中使用,意即其所修饰的对象为常量((immutable)),它不能被修改,并存放在常量区。 其次,对于+,不能改变自身的值,因此,我们需要重新拷贝一下this指针对应的对象,对拷贝后的对象进行操作,这样才不会改变原本的对象,。 因此,C++规定:将括号中带有int的规定为后置++,不带int的为前置++ 。
C++作为一门面向对象的语言,自然具备了面向对象的三大特征:封装,继承,多态。在学习多态性质的过程中,发现了C++与其他语言很大的区别(坑?)。 在C++中的=操作符的使用与C++呈现的内存模型似乎并不是我所习惯的模式,在拷贝与引用两个不同操作之间摇摆,还是很容易写出存在问题的代码,所以也就引出了今天这篇文章,我们来聊聊=操作符背后的故事。 好吧,上面两段代码我想会让很多Java或Python的程序员深感困惑,看起来C++和我们熟悉的语言想去甚远。 在C++之中,= 操作符代表一个拷贝 bird b = p 代表b是一个bird对象,通过p拷贝,重新生成一个新的bird对象。所以这是一个拷贝操作,拷贝的是一个对象。 (对象拷贝是深拷贝,因为生成新的对象,和原对象不使用同样的内存空间). Python 同Java一般,都是对象引用。
4. C++中struct也可以定义类,C++兼容C中struct的用法,同时struct升级成了类,明显的变化是struct中可以定义函数,⼀般情况下我们还是推荐用class定义类。 5. ⼀个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量。 4. 但是成员函数并没有保存在每个对象里面。 2. 所以计算类的大小时候,只计算成员变量占用的内存,并不计算成员函数占用的内存。 3. C++规定类实例化的对象也要符合内存对齐的规则。 4. (无参数,有参数,缺省参数) 4. 对象实例化时,系统会自动调用对应的构造函数。 5. ⼀个局部域的多个对象,C++规定后定义的对象先析构。
C++类和对象 C++中对象的类型称为类,类代表了某一批对象的共性和特征,类是对象的抽象,而对象是类的具体实例, 类是抽象的,不占用内存,而对象是具体的,占用 存储空间,这点很重要,读者需要牢记。 C++声明类类型 类是用户自己指定的类型,如果程序中要用到类类型,必须自己根据需要进行声明,或者使用别人已设计好的类,C++标准本身并不提供现成的类的名称、结构和内容,C++声明一个类类型和声明一个结构体类型类似 C++如果在类体中既不写关键字private,又不写public,就默认为private。 案例:C++创建学生类。 stu1与stu2 C++类和对象 | 类和对象 更多案例可以go公众号:C语言入门到精通
public: //成员函数 void func() { cout<<"void func()"<<endl; } private: //成员变量 int _a; } 二,默认成员函数的种类 C+ C++有六个默认的成员函数也就是说这六个成员函数如果我们自己不写编译器就会自动生成。至于为什么要搞这些默认成员函数待学完这些默认成员函数你自然就会明白! 下面我们来看栈这个类: class Stack { public: Stack(int n = 4) { cout << "Stack(int n = 4)" << endl; _a = C++规定了只要是自定义类型的对象进行拷贝行为就要去调用拷贝构造,无论是自定义类型的传值传参还是传值返回都要去调用拷贝构造。 24); // 构造 Date d2(d1); // 拷贝构造 构成 副本(原对象) //直接赋值也是拷贝的意思 Date d4 = d1; // 拷贝构造
stack.h #include <iostream> class Stack { public: void Init(int capacity = 4); void Push(int x); void 4 : _capacity * 2; int* newNext = (int*)realloc(_next, sizeof(int) * newcapacity); if (newNext == +中兼容C语言,C++编译器也支持struct关键字,满足结构体的功能C,不仅如此C++还对它进行了升级,也支持类的定义格式。 下面使用C++实现栈。 1.2访问限定符 可以发现,在上述实现类中,使用了 pulic、private这两个是访问限定符,用于限定对类成员访问的权限 C++将对象的属性与方法封装在一起,通过访问权限选择性的将接口提供给外部使用
C++中struct也可以定义类,但是struct同C语言相比是升级成了类,和class的用法几乎类似。 { } int _number; }; struct c2 { void number() { } int _number; }; 访问限定符 C+ C++给定实例化对象也要符合内存对齐规则。 对齐规则 第一个成员在结构体偏移量为0的位置。 ,C++允许我们通过运算符重载的形式指定新的含义。 C++固定对类类型对象使用运算符时,必须转换成调用对应的运算符重载,若没有对应的重载就会编译错误。
在 C++ 中,由于其手动内存管理的特性,使用对象内存池可以显著提高程序的效率,尤其是在需要频繁创建和销毁对象的场景中。 1. 对象内存池的概念 对象内存池的核心思想是维护一个对象的集合(池),当需要使用对象时,从池中获取一个对象,而不是每次都创建新的对象。当对象不再使用时,它会被放回池中,而不是被销毁。 C++ 中的对象内存池实现 2.1 基本实现 以下是一个简单的 C++ 对象内存池的实现示例: #include <iostream> #include <vector> #include <memory 复杂性:实现和管理对象池的逻辑可能会增加代码的复杂性。 对象状态管理:需要确保对象在被重用时处于有效状态,可能需要重置对象的状态。 4. 在实际应用中,开发者需要根据具体需求和场景选择合适的对象池实现方式。 5.1 进一步阅读 C++ 对象池模式 C++ 内存管理 C++ 线程安全编程 再次欢迎关注、点赞、收藏!
一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量 做个比方,类就类似于建房子的图纸,一个图纸可以建造多个多个房子。 类对象模型 如何计算类的大小呢? 只能在“成员函数”的内部使用 this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给 this形参。所以对象中不存储this指针。 ,但如果每次创建对象时都调用该方法设置 信息,未免有点麻烦,那能否在对象创建时,就将信息设置进去呢? 析构函数 析构函数恰好与构造函数相反,在C语言写接口的时候,总是会忘记调用销毁的函数destroy,所以C++引入了析构函数,当一个结构体变量出了这个作用域时就会调用析构函数进行销毁, 析构函数是特殊的成员函数 注意:析构 函数不能重载 对象生命周期结束时,C++编译系统系统自动调用析构函数。 关于编译器自动生成的析构函数,是否会完成一些事情呢?
; void test() { Bell b; Widget &w =b; w.show(); } test函数对应的汇编代码如下: _Z4testv ebp) //Widget &w=b movl -24(%ebp), %eax //eax=&w movl (%eax), %eax //eax=vptr4Bell movl (%eax), %eax //eax = vptr4Bell[0] subl $12, %esp pushl -24(%ebp .L5 call __stack_chk_fail .L5: leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc test函数对应的伪码如下: test() { Bell::Bell(&b); Widget *w=&b; (w
C++指向对象的指针 C++建立对象时,编译系统会为每一个对象分配一定存储空间,让存放其成员。对象空间的起始地址就是对象的指针,可以定义一个指针变量,用来存放对象的指针。 定义指向类对象的指针变量的一般形式为 类名 * 对象指针名; 可以通过对象指针访问对象和对象的成员 C++指向对象成员的指针 在C++中,对象是有地址的,存放对象初始地址的指针变量就是指向对象的指针变量 数据的指针变量 定义指向对象数据成员的指针变量的一般形式为 数据类型名 *指针变量名; 2、指向对象成员函数的指针 C++定义指向对象成员函数的指针变量的方法,与定义指向普通函数的指针变量方法有所不同 定义指向公用成员函数的指针变量的一般形式为 数据类型名 (类名∷*指针变量名)(参数表列); 指针变量指向一个公用成员函数的一般形式为 指针变量名=&类名∷成员函数名; 案例:C++对象指针的使用 以上,如果你看了觉得对你有所帮助,就给小林点个赞叭,这样小林也有更新下去的动力,跪谢各位父老乡亲啦~ C++学习路线 C++开发工具 VC6.0、Devc++、VS2019使用教程 100道C语言源码案例请去公众号