C++复习9.面向对象编程
C++ 面向对象编程概述 20131001
一些基本概念:封装、继承、组合、虚函数、抽象基类、动态绑定、多态性等等
1.一个笑话:如果坐在后排聊天的同学能够像中间打牌的同学那样安静的话,那么就不会影响到前排睡觉的同学了。
C++的封装机制控制信心的访问,C++中最根本的改变就是把函数放进结构体中,进而产生了C++的类。类可以把数据和函数绑定在一起,其中数据表示类的属性,函数表示类的行为,也就是成员函数。C++中提供public, protected, private 用于控制属性和函数的访问权限。
2.类的继承特性
子类会继承父类中的所有成员变量和成员函数,只是根据权限,有些是无法访问的。同时继承可以是多重继承的,一个比较重要的用途就是在已有接口和实现类的基础上创建自己的接口和实现类。
3.类的组合特性
组合(Composition)是一种类的符合技术,用于表示累的整合和部分的关系,这种关系不是派生。并不是所有的C++class 都要使用继承,有些类之间的关系是聚合或者引用。
4.动态特性
在绝大多数的情况下,程序的功能是在编译的时候就已经确定下来了,我们称为静态特性。反之,如果程序的功能是在运行的时候才确定下来的话,称之为动态特性。动态特性是面向对象语言最强大的功能之一,因为他是在语言层面上支持程序的可扩展性。C++虚函数、抽象基类、动态绑定和多态 实现C++语言的动态特性。
虚函数:
在基类中使用virtual 关键字修饰函数,然后再派生类中重写该函数,叫做Override,但是虚函数不是实现多态的唯一手段,其他的语言或许会采用其他的方式。
一旦类中的一个函数被声明为虚函数,那么器派生类的对应函数也自动变成虚函数,但是为了提高程序的清晰性,最好在派生类中的函数前面使用virtual关键字修饰。
抽象基类:
有时候有些类是不可以被实例化的,就叫做抽象基类(Abstract Class)能被实例化的类叫做具体类或者实体类(Implementation class)。抽象基类的唯一目的就是让其派生类继承并且实现抽象基类的接口。
如果我们将基类的虚函数声明为纯虚函数,那么该类就被定义为了抽象基类,纯虚函数就是声明的时候初始化为0。因为纯虚函数不知打如何实现,所以必须依靠派生类实现纯虚函数。C++中之纯虚函数才可以被指向0,这样告诉编译器不要为该函数编址,从而阻止该类的实例化行为。抽象基类的主要作用是显现接口和实现的分离:不仅要把数据成员信息隐藏,还要实现完全隐藏,只保留一些接口供外部调用。
动态绑定:
又叫做运行时绑定,动态绑定技术是如何实现的?程序之所以能够在运行的时候选择正确的虚函数,必定隐藏了一段运行时进行对象类型判断或是函数寻址的代码。
每一个具有虚函数的类都叫做多态类,这个虚函数是从基类继承来的或者是自己新增加的。C++编译器必须为每一个多态类至少创建一个虚表(Virtual -Table),其实就是一个函数指针数组,其中存放着该多态类的所有虚函数地址和该类的类型的信息。每一个多态对象都会隐含的包含了一个隐含的指针成员,指向所属类型的虚表,就是vptr。
实际上虚函数的动态绑定并没有使用到这个类型的信息,而是采用的运行时函数寻址技术,该类型的信息主要用在RTTI技术上。
多态数组:不要在数组中直接存放多态对象,而是换之以基类的指针或者是基类的智能指针。
5.C++对象模型
构造函数、拷贝和赋值函数、析构函数、静态成员、虚函数、继承、组合、动态对象的创建、RTTI等等,还有一些结合底层的知识内存映像、vtable的构造、vptr的插入和初始化实际、构造函数和析构函数的自动调用实际、对象的构造和析构次序、临时对象的好粗啊关键和销毁、RTTI底层实现技术。
对象的内存映像:
首先了解对象是如何在内存中布局:
非静态数据成员被存储在每一个对象中作为对象专有的数据成员(用户数据区);静态成员变量被提取出来放在程序中的静态数据区内,为该类的所有对象共享,只有一份(静态数据区);静态和非静态的成员函数都会被提取出来放在程序中的代码段中,并且为该类的所有对象共享,因此每一个成员函数只有一个代码实体(代码段)。
因此构成对象本身的只有数据,任何成员函数都不属于任何一个对象,而非静态成员函数于对象之间的关系是绑定的,绑定的中介是this指针。
增加继承和虚函数的类的对象模型变得复杂:
派生类继承基类的非静态数据成员,并且作为自己对象的专有数据成员;
派生类继承基类中的非静态成员函数,并且可以想自己的成员函数一样访问;
为每一个多态类简历一个虚函数的指针数组vtable,该类中所有的虚函数的地址保存在这个虚函数表中;
多态类的每一个对象中安插了一个指针成员vptr,类型是指向函数指针的指针,他总是指向所属类的vtable,也就是说vptr当前的对象是什么类型,就会指向这个类型的vtable。Vptr是C++中隐含的数据成员;
如果基类中插入vptr,则派生类会继承和重用该vptr;
如果派生类是继承多个基类,那么在每一个继承的分支上都会有一个vptr,编译器也为之生成了多个vtable;
Vptr在派生类对象中的相对位置不会随着继承层次的加深而改变,一般都会放在对象的最前面;
为了支持RTTI技术,为每一多态类创建一个type_info对象,并且把其地址保存在vtable中的一个固定的位置。
虚表是存储在静态存储区域的。
隐含成员:
一个对象的内存映像并不是和代码中的一样,虽然在编程的角度不需要了解这些底层的知识,但这些对于我们编写代码十分有帮助。
一个C++符合类型对象,其可能包含的隐含的成员:若干个vptr,默认的构造函数、默认的拷贝构造函数、析构函数、默认的拷贝赋值函数。
C++中对象模型要充分考虑到对象数据成员的空间效率和访问速度,以优化性能。另外内存空间占用不是简单的把成员加在一起:因为编译器可能安插了额外隐含的数据成员;对于存取效率的考虑,需要考虑增加填补字节使对象的边界能够对其到字长(Word)
C++如何处理成员函数:
程序中的函数保存在程序的代码段,并且是只有一份。对于两个编译单元中的完全相同的static全局函数,编译器会将他们当做不同的函数处理,分别生成可执行的代码。
C++通过Name-Mapping技术实现的吧每一个成员函数都转换成名字唯一的全局函数,并且通过对象、指针或者引用对么一个成员函数的调用语句改写成响应的全局函数的调用函数。
C++中的静态成员:
static生命的声明期限是永久,因此类的静态成员数据和静态成员函数在程序开始的时候创建在程序结束的时候销毁。因此他们不依赖对象的存在而存在,不需要通过对象来访问,本质上就是一个全局变量或者函数。
Class中静态数据成员可以直接在class定义中初始化,但是要清楚,这只是声明并且分给他们一个初始值而已,而且在一个编译单元中把它定义一次。
静态函数设计思想是:如果一个成员函数访问了对象的数据成员,那么给他传入一个this指针是必须的,但是有时候一个成员函数不会访问对象的任何数据成员,因此没有必要传递this指针。这就是后来的C++静态成员函数。
静态成员函数也是需要Name-Mapping处理的并且提取到class之外,不同的是他不需要this指针参数。可以直接使用class name的作用域符直接应用.
追梦的飞飞
20131001 于广州中山大学
C++复习9.面向对象编程的更多相关文章
- [.net 面向对象编程基础] (1) 开篇
[.net 面向对象编程基础] (1)开篇 使用.net进行面向对象编程也有好长一段时间了,整天都忙于赶项目,完成项目任务之中.最近偶有闲暇,看了项目组中的同学写的代码,感慨颇深.感觉除了定义个类,就 ...
- Java面向对象编程基础
一.Java面向对象编程基础 1.什么是对象?Object 什么都是对象! 只要是客观存在的具体事物,都是对象(汽车.小强.事件.任务.按钮.字体) 2.为什么需要面向对象? 面向对象能够像分析现实生 ...
- ndk学习之c++语言基础复习----面向对象编程
关于面向对象编程对于一个java程序员那是再熟悉不过了,不过对于C++而言相对java还是有很多不同点的,所以全面复习一下. 类 C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程 ...
- c++primer复习(六)—面向对象编程
1 C++中,通过基类的引用(或指针)调用虚函数时,发生动态绑定,两个条件(基类引用或指针.虚函数)缺一不可 虚函数的默认实参将发生静态绑定 2 继承层次的根类一般都需要定义虚析构函数 3 任意非st ...
- [.net 面向对象编程基础] (14) 重构
[.net 面向对象编程基础] (14) 重构 通过面向对象三大特性:封装.继承.多态的学习,可以说我们已经掌握了面向对象的核心.接下来的学习就是如何让我们的代码更优雅.更高效.更易读.更易维护.当然 ...
- .net 4.0 面向对象编程漫谈基础篇读书笔记
话说笔者接触.net 已有些年头,做过的项目也有不少,有几百万的,也有几十万的,有C/S的,也有B/S的.感觉几年下来,用过的框架不少,但是.net的精髓一直没有掌握.就像学武之人懂得各种招式,但内功 ...
- php面向对象编程学习之高级特性
前几天写了一篇关于php面向对象基础知识的博客,这两天看了php面向对象的高级特性,写出来记录一下吧,方便以后拿出来复习. 面向对象除了最基本的定义类之外,最主要就是因为面向的一些高级特性,运用这些高 ...
- 洗礼灵魂,修炼python(40)--面向对象编程(10)—定制魔法方法+time模块
定制魔法方法 1.什么是定制魔法方法 首先定制是什么意思呢?其实就是自定义了,根据我们想要的要求来自定义.而在python中,其实那些所谓的内置函数,内置方法,内置属性之类的其实也是自定义出来的,不过 ...
- Java复习9网路编程
Java 复习9网路编程 20131008 前言: Java语言在网络通信上面的开发要远远领先于其他编程语言,这是Java开发中最重要的应用,可以基于协议的编程,如Socket,URLConnecti ...
随机推荐
- Mybatis 一对一、一对多、多对多
一对一返回resultType <!-- 查询订单关联查询用户信息 resultType --> <select id="findOrderCustom" res ...
- 后缀自动机模板 SAM
一点疑问: 当创建nq节点时,要不要把nq的cnt标记赋值为1? 讲道理nq节点也是代表一个子串啊,不过网上的模板都没赋值. 2017.9.18 update: 把memset部分重写,改成用节点用到 ...
- cocos2dx lua invalid 'cobj' in function 'lua_cocos2dx‘ 躺坑
for 循环中保存了创建的 Node节点到 userdata 数据结构中 再次引用发现 一直报 LUA ERROR: [string ".\framework/cocos2dx/NodeEx ...
- QML中的state 状态
QML中的状态其实很好理解,任何事物在某一事件都是有一个状态的. 比如你看到的一个窗口,这个时候里面的文字和图片正处于某个状态中.比如一个超链接,你点击了,发现颜色变了,你按了Ctrl+A,整个窗体好 ...
- JqGrid 隐藏水平滚动条完美解决方案
我有强迫症,网上找的几个看着就不舒服 不用更改样式表,隐藏最右侧的边框. .ui-jqgrid .ui-jqgrid-bdiv{ overflow-x: hidden; } 不用通过js控制加1px ...
- C/C++结构体语法总结
转自:http://blog.csdn.net/dawn_after_dark/article/details/73555562 结构体简介 结构体属于聚合数据类型的一类,它将不同的数据类型整合在一起 ...
- Django学习笔记之Queryset的高效使用
对象关系映射 (ORM) 使得与SQL数据库交互更为简单,不过也被认为效率不高,比原始的SQL要慢. 要有效的使用ORM,意味着需要多少要明白它是如何查询数据库的.本文我将重点介绍如何有效使用 Dja ...
- MySQL-5.7 备份与恢复
一.备份分类 按介质分类: 物理备份 指通过拷贝数据库文件方式完成备份,适用于数据库很大,数据重要且需要快速恢复的数据库. 逻辑备份 指通过备份数据库的逻辑结构和数据内容的方式完成备份,适用于数据库不 ...
- DNSmasq安装配置
dns安装配置yum -y install dnsmasq dns配置文件vi /etc/dnsmasq.confresolv-file=/etc/resolv.dnsmasq.confaddn-ho ...
- logstash运输器以及kibana的更多操作
为了达到不会因为ELK中的某一项组件因为故障而导致整个ELK工作出问题,于是 将logstash收集到的数据存入到消息队列中如redis,rabbitMQ,activeMQ或者kafka,这里以red ...