我对面向对象编程的一些理解

1. 面向对象编程的主导问题

  • C++三大特性
    • 封装、继承、多态。
    • 封装:目的是实现代码模块化。
    • 继承:目的是实现代码扩展。
    • 多态:目的是分为静态多态和动态多态。
  • 什么是程序?
    • what: 一段编译器能听懂的指令
    • input ----> process —> output
    • why: 自然语言有歧义,用于计算机运算效率不高
    • how: 根据问题,构建数据类型+算法---------------如何写好代码?
  • 什么是按值传递
    • 传递的是值的拷贝,也就是说传递后就互不相关了
    • 如何取消按值传递:引用传递,其实传递的为引用的地址,也就是变量所对应的内存空间的地址。
  • 什么是对象?
    • 对象是数据类型的一个实例
    • 每个实例都是类的一个对象
  • 什么是面向对象编程?
    • 是一种编程模式,将需用到的数据类型、方法定义为类,涉及数据封装、继承、多态等
    • 本质:抽象出问题涉及的对象,设计一组抽象的类型,建模
    • 结构类型是一种新的数据类型
    • 数据隐藏:对象的属性应该在合理范围内,不允许直接访问,可通过成员函数间接访问
  • 如何使用面向对象编程?
    1. 定义与问题相关的实体类型,根据问题解决方案确定每个类型的特性和操作。即抽象出类和方法的声明
    2. 编写类定义,对这些类型编码。即实现方法
    3. 根据对象,使用直接利用这些对象的操作编写解决问题的方案。即串联方案,解决问题
  • 什么是类?
    • 类是一种自己定义,用于描述对象,满足应用程序需求的数据类型,定义类用class,内聚某个问题所需的数据类型
    • 类成员默认私有,可用访问指定符划定类成员显示区域:public、protected、private
    • 类对象的大小一般是所有数据成员的大小总和,不包括静态数据成员的size
  • 什么是封装?
    • 封装就是用一个结构类型来描述对象属性和对象操作
  • 什么是继承?
    • 继承是一个类可以获得另一个类的特性的机制
    • 继承是一种代码重用的形式,允许程序员基于现有类开发新类。现有类通常称为"基类"或"超类",新类通常称为"类"或"派生类"。
    • 继承的好处:继承最大的好处是代码的重用,与它同样重要的是它带来了多态(继承是实现多态的基础)
  • 什么是多态?
    • 不同时刻有不同形态,使用指针或引用调用对象成员函数。编译时未确定,执行时决定指向哪个成员函数
    • 多态性好处:设计与编译时不能确认处理哪种类型的对象,只能在运行时确定(取决于用户的输入类型),而多态性可以满足这种需求,一般用于交互式应用程序
  • 什么是构造函数?
    • 所谓构造函数,就是与类同名的函数,它与普通函数的区别在于,它没有返回类型,也不会返回 void。
    • 构造函数的作用:创建类对象时,为类成员赋初值与验证初值
    • 如果类中定义了构造函数,则不能用初始化列表类初始化对象
    • 默认构造函数,调用不指定参数列表,不用括号
  • 什么是析构函数?
    • 类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。
    • 析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。
    • 析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
    • 对象的释放顺序与创建它们的顺序相反,像栈一样,先进后出。
  • 什么是副本?
    • 拷贝机制,编译器会对所有入参制作临时副本
    • 函数内对入参的操作均为对副本的操作
    • 函数的参数,会对数组传地址,不会有副本机制,为了节约内存,数组传递的是指针
    • 函数返回值有副本机制,返回的时候,另外再保存一份,当获取到返回值后,原来内存的数据就被销毁了
  • 什么是副本构造函数?
    • 一种特殊的构造函数,参数为类对象。用一个已创建的对象来初始化同类的另外一个对象,即对象copy
    • 创建对象时,不用显示调用副本构造函数,只需将对象作为入参传入构造函数,编译器则会调用副本构造函数,创建对象副本。但只针对简单类
    • 入参必须为引用,否则会递归call构造函数
    • 入参必须用const修饰,因为副本构造函数仅创建副本,不修改原对象
    • 缺点:两个对象的指针数据成员指向了同一块内存空间,可通过自已定义副本构造函数解决
    • 如何禁止副本构造函数:声明为private,可以不实现
  • 什么是内联函数?
    • 类内定义的函数均为inline函数
    • 函数声明在类内,但定义在类外的函数,看是否有inline修饰
    • 一般函数的代码段只有一份,放在内存中的某个位置上,当程序调用它是,指令就跳转过来;当下一次程序调用它是,指令又跳转过来;而内联函数是程序中调用几次内联函数,内联函数的代码就会复制几份放在对应的位置上
    • 内联函数的定义包含在.h头文件中,只有不是内联函数的定义才应放在.cpp文件中
  • 什么是隐式类型转换?
    • 隐式类型转换即偷偷把给定的类型转换为另外一种类型,不用显示强转。
    • 对于类构造函数只有一个参数或只有一个无默认值入参,加上explicit表示显示转换,则可避免隐式转换
  • 什么是友元?
    • 在类定义中用friend声明友元函数、友元类
    • 友元关系不能传递、不能反向
    • 类外部的函数被指定为友元,则外部函数与类内部成员无异,可随意访问类内所有数据成员、成员函数
  • 什么是this指针?
    • 指向类实例对象地址的指针变量
    • 返回类实例对象地址是需显示使用this指针变量
  • 什么是引用?
    • 引用即一个变量的别名,与目标变量占用同一片内存
    • 引用即指针常量,指向的地址不改变
    • 引用声明时必须初始化,初始化后不能修改值
    • 写法:数据类型 &引用名 = 目标变量名;
    • 数组不能引用,可以对数组单个变量进行引用
  • 链表相对数组的优势?
    • 链表长度不固定
    • 链表可随意节点增删

2. 访问指定符

  • 两个方面:类成员的访问指定符、基类访问指定符,类成员与基类的默认访问指定符均为private
  • private是自己私有的,protected是可以让孩子知道的,public是公开的!
    • public:可以被任意实体访问
    • protected:只允许子类及本类的成员函数访问
    • private:只允许本类的成员函数访问。外部不能访问。获取私有数据成员的唯一方式是通过构造函数或成员函数

3. const

  • 对象声明为const,只能调用被声明为const的成员函数,因为对象的this指针变量不能被修改

  • const只能应用于类的成员函数,函数指定为const则不能修改调用它的对象,const只能用于属于类的成员函数

  • const_cast是一种C++运算符,主要是用来去除复合类型中const和volatile属性(没有真正去除)。

    • 变量本身的const属性是不能去除的,要想修改变量的值,一般是去除指针(或引用)的const属性,再进行间接修改。

    • 用法:const_cast(data)

4. 类的静态数据成员

  • 无论类有多少个对象,静态数据成员只有一份,而非静态数据成员都是类中非静态数据成员的副本,每个对象有一份副本
  • 即使未创建类的对象,类的静态数据成员依然存在
  • 在类声明外部初始化静态数据成员,初始化时使用类名和作用域解析运算符限定成员

5. 类的操作

  • 对象的数据成员包含此对象指针,可使对象链接起来,则将数据组织为结构、链表等
  • 对象指针、对象引用作为函数参数,作为参数传递比直接传递效率更高,不用复制操作
  • 开发容器类时,需仔细考虑该类的数据成员是否为源对象的副本
  • 控制对类的访问:嵌套类

6. 运算符重载

  • 不能重载的运算符::: ?: . .* sizieof
  • 确保标准运算符的重载版本与其原始用法含义基本保持一致
  • 二元运算符‘X’重载:
    • 写法:operator+‘‘需要重载的运算符’’,比如:bool operator<()
    • 类成员函数:返回类型 operator X(类型 右操作数)
    • 非成员函数:返回类型 operator X(类类型 左操作数,类型 右操作数)
    • 非成员函数:返回类型 operator X(类型 左操作数,类类型 右操作数)
  • 一元运算符’Op’重载:
    • 类成员函数:类类型& operator Op()
    • 全局函数:类类型& operator Op(类类型&)

7. 继承

  • 派生类对象应代表有意义的基类对象,比如狗是一种动物,狗是有意义的、具体的,而动物无意义、不具体
  • 三种测试:
    1. 种类测试:派生类应描述基类所表示对象的一个子集
    2. 基类是否有特性不能用于派生类?如果没有,继承就是可行的
    3. 没通过种类测试,则试下包含测试:类对象包含另一个类的实例,采用聚合
  • 多重继承:派生类可以有任意多个直接基类,与单一继承相对(只使用一个基类)
  • 虚基类,关键字virtual。为了避免同一基类的多个子对象被派生类多次包含,把重复的类声明为虚基类。
  • 访问派生类的继承成员有两个因素控制:基类成员的访问指定符、派生类声明中基类的访问指定符

8. 虚函数和多态

  • 基类指针:基类指针可存储派生类对象地址,反过来不行,基类没有描述完整的派生类对象

  • 什么是多态性:任何时刻,基类指针都可以指向任何派生于此基类的类对象。

    • “静态类型”:指针在声明时指向基类对象,通过静态解析的基类指针来调用函数,都会调用基类的函数。不取决于它指向的对象

    • “动态类型”:当指向派生类对象时,它会根据指向的对象类型而变化。

    • 类描述为多态性,那么它是至少包含一个虚函数的派生类

  • 多态性好处:

    • 设计与编译时不能确认处理哪种类型的对象,只能在运行时确定(取决于用户的输入类型),而多态性可以满足这种需求,一般用于交互式应用程序
  • 多态性的成本:

    • 内存占用与程序文件更大,因为有vtable指针表
    • 虚函数调用速度略慢,开销很小,可忽略
  • 什么是虚函数:把一个函数声明为基类的虚函数,则派生于此基类的任何类中的此函数都是动态绑定的。用关键字virtual**声明(注意不是定义)**虚函数,虚函数是一个工具

    • 使用对象或直接成员选择运算符调用虚函数-------静态解析,编译时解析
    • 通过指针或引用调用虚函数---------动态解析,调用时解析
    • 生效规则:如果派生类与基类中虚函数的函数名、参数列表、返回类型或者修饰符(比如const)不同,则虚函数机制失效,编译时固定为静态绑定。访问指定符不同不影响虚函数生效
    • 模板函数不能为虚函数
    • 虚函数默认值为编译时决定
  • 纯虚函数

    • 定义:基类虚函数只声明,不实现,在类的声明中加上“ = 0”(加在参数列表后)
  • 抽象类

    • 定义:包含纯虚函数的类称为抽象类
    • 存在的意义:定义派生于它的其他类,不允许创建抽象类的实例
    • 抽象属性可继承:派生类如果未定义抽象基类的纯虚函数,纯虚函数会原封不动地继承下来,则派生类也是一个抽象类
  • 静态类型转换 static_cast

    • static_cast比较接近于C语言中的强制转换,多用于不同的基本数据类型的转换
    • 在编译期间转换,转换失败的话会抛出一个编译错误
    • 用法:static_cast(data)
      该运算符把data转换为newType类型,但没有运行时类型检查来保证转换的安全性
    • 将派生类指针转换为基类指针是安全的;反之,将基类指针转换为派生类指针是不安全的
  • 动态强制转换 dynamic_cast

    • 用法:dynamic_cast(data)

    • dynamic_cast 会在程序运行期间借助 RTTI 进行类型转换,这就要求基类必须包含虚函数

    • newType 和 data 必须同时是指针类型或者引用类型。换句话说,dynamic_cast 只能转换指针类型和引用类型,其它类型(int、double、数组、类、结构体等)都不行。

      对于指针,如果转换失败将返回 NULL;对于引用,如果转换失败将抛出std::bad_cast异常。

  • 虚析构函数

    • 如果基类包含虚函数,则基类的析构函数应声明为virtual
    • 析构函数声明中增加virtual关键字,告知编译器,通过指针或引用调用的析构函数是动态绑定的,运行时动态选择
  • 运行器件标识类型

    • typeid 的操作对象既可以是表达式,也可以是数据类型
    • 用法:
      • typeid( dataType )
      • typeid( expression )
    • typeid 会把获取到的类型信息保存到一个 type_info 类型的对象里面,并返回该对象的常引用
  • 类成员指针

    • 数据成员指针:
      • 不是类对象的数据成员指针,而是类成员的指针。它只是在和Box类型对象一起使用时,才指向内存中的某个位置
      • 在类包含相同类型的几个数据成员时,就可使用数据成员指针
    • 成员指针选择运算符:
      • 直接指针选择运算符:“.*” = 直接成员选择运算符“.” + 解除引用运算符"*"
      • 间接指针选择运算符:“->*” = 间接成员选择运算符"->" + 解除引用运算符“*”
    • 成员函数指针:
      • 与函数指针类似。
      • 注意调用运算符“()”的优先级高于选择运算符"->",所以必须在调用前给函数加上括号
      • 为类class_type的函数声明一个指针写法:return_type (class_type::*pointer_name) (parameter_type_list);
      • 声明函数指针同名词:typedef return_type(class_type::*ptr_typename)(parameter_type_list)
    • 成员函数的参数可以是成员的指针

9. 输入输出操作

  • 流:程序中输入或输出设备(数据的来源或目的地)的抽象表示。流是外部设备与计算机内存之间流动的一系列字节
  • 数据传输模式:文本模式、二进制模式
  • 流的读写操作:提取和插入运算符读写各种类型的数据、读写字符

10. 标准模板库 STL

  • 三类工具:容器、迭代器、算法
  • 序列容器:
    • vector
      • 适合尾部增删,类似数组
      • size()
      • capacity()
    • deque
      • 适合头尾增删,double-ended queue
      • size()
      • 无capacity函数,容器大小始终等于其容量
    • list
      • 适合中间增删,类似链表
      • pPrev
      • pNext
  • 关联容器:
    • map<Key, T>
    • multimap<Key, T>
    • set
    • multiset
      • map\set键值唯一
      • multimap\multiset键值可重复
  • 迭代器
    • 迭代器是一种智能指针
    • 从容器中获得的迭代器特性取决于容器类型
  • 算法
    • 算法是STL中最大的工具集合
    • 算法有三大类:
      • 不修改序列的操作
      • 修改序列的操作
      • 排序、合并和相关操作
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值