Part 8: 面向对象(第15章)

// @author:       gr
// @date: 2015-01-09
// @email: forgerui@gmail.com

一、OOP

面向对象程序设计的核心思想是数据抽象、继承和动态绑定。

数据抽象:可以将类的接口与实现分离

继承:可以定义相似的类型并对其相似关系建模

动态绑定:在一定程度上忽略相似类型的区别,使用统一的方式使用它们的对象

二、定义基类或派生类

  1. 基类通常应该定义一个虚析构函数,即使该函数不执行任何实际操作。

  2. virtualoverride关键字只允许在类内使用,类外使用会报错。

  3. 派生类中,C++11标准允许使用override关键字显式地注明它使用某个成员函数覆盖了它继承的虚函数。

  4. C++11中可以使用final关键字防止继承的发生。

     class Last final {
    private:
    int a;
    };
  5. 在覆盖基类的函数时,大意将参数列表写错,没有构成覆盖,将会是两个独立的函数。如果使用override关键字,编译器会报marked override, but does not override的错误,提示有当前的问题。使用override需要保持基类和派生类的函数形式一致,并且基类的函数要声明为virtual

  6. 派生类可以转换到基类,但不存在基类像派生类的转换。从派生类向基类的转换只对指针或引用类型有效。

三、虚函数

  1. 回避虚函数的机制

    强迫执行虚函数的某个特定版本,使用作用域运算符可以实现这一目的:

     double undiscounted = baseP->Quote::net_price(42);  //使用基类Quote中的net_price函数
  2. 多态性

    使用虚函数,通过动态绑定实现,在运行时进行解析。

四、抽象基类

抽象类不能创建对象,只能作为接口,其它类继承它。

含有纯虚函数的类是抽象类。

五、访问控制与继承

  1. 派生类的成员或友元只能通过派生类对象来访问基类的受保护成员。派生类对于一个基类对象中的受保护成员没有任何访问特权。

     class Base{
    protected:
    int prot_mem;
    };
    class Sneaky : public Base{
    friend void clobber(Sneaky&);
    friend void clobber(Base&);
    int j;
    }; //正确:clobber能访问Sneaky对象的private和protected成员
    void clobber(Sneaky& s){s.j = s.prot_mem = 0;}
    //错误:clobber不能访问Base的protected成员
    void clobber(Base& b){b.prot_mem = 0;}

    上面的第二个clobber函数因为不是Base的友元,所以无法访问Base的protected成员。

  2. 派生访问说明符的目的是控制派生类用户(包括派生类的用户、派生类的派生类)对于基类成员的访问权限。

     class Base{
    public:
    void pub_mem();
    protected:
    int prot_mem;
    privated:
    int priv_mem;
    };
    class Pub_Derv : public Base{
    int f() {return prot_mem;}
    char g() {return priv_mem;}
    };
    class Priv_Derv : private Base{
    int f1() const {return prot_mem;}
    };
    Pub_Derv d1;
    Priv_Derv d2;
    d1.pub_mem(); //正确:pub_mem在派生类中是public的
    d2.pub_mem(); //错误:pub_mem在派生类中是private的

    这样,private派生访问说明符表明继承的成员是private,用户无法访问这个成员。使用public继承便可以访问。

    class默认使用的是private继承,struct默认使用的public继承。

  3. 友元与继承

    友元关系不能继承。基类的友元在访问派生类成员时不具有特殊性,同样,派生类的友元也不能随意访问基类的成员。

     class Base{
    friend class Pal; //Pal在访问Base的派生类不具有特殊性
    };
    class Pal{
    int f(Base b){return b.prot_mem;}
    };

六、继承中的类作用域

在编译时进行名字查找

作用域从派生类到基类查找成员。

如果两个成员名字相同,派生类的名字将隐藏基类的名字,但基类中的变量仍然存在。使用作用域运算符可以使用隐藏的名字。

名字查找优先于类型检查

struct Base{
int memfcn();
};
struct Derived : Base{
int memfcn(int);
}
Base b;
Derived d;
b.memfcn(); //正确,调用Base::memfcn()
d.memfcn(42); //正确,调用Derived::memfcn(int)
d.memfcn(); //错误,调用Derived::memfcn(int),参数类型不一致
d.Base::memfcn(); //正确,调用Base:memfcn()

从上面可以看出,查找到相同的名字就停止查找,所以基类的函数被隐藏了。之后再进行参数匹配,发现匹配不对,将会报错。

覆盖重载的函数

派生类可以覆盖重载函数的0个或多个实例。如果派生类希望所有的重载版本对于它来说都是可见的,那么它就要覆盖所有的版本,或者一个都不覆盖

有时,只需覆盖一些而非全部函数时,不都不覆盖每个基类中的每个版本。

解决方案是为重载的成员提供一条using声明语句,使用using可以将子类的所有重载函数放入到当前作用域,这时在添加需要覆盖的函数。

class Base{
public:
//定义三个版本的fcn函数
virtual void fcn();
virtual void fcn(int);
virtual void fcn(double);
};
class Derived : private Base{
public:
//使用using引入Base中的fcn重载函数
using Base::fcn;
//只覆盖int版本
virtual void fcn(int a);
};

七、构造函数与拷贝控制

  1. 基类虚析构函数
  2. 合成拷贝控制与继承

    如果基类的函数是不可访问或者删除的,则派生类的函数也将是被删除的。

八、容器与继承

  1. 容器中存放基类型,将派生对象转换为基对象,派生部分将被“切掉”。

  2. 解决上面的问题,可以在容器中存放(智能)指针而非对象

     vector<shared_ptr<Quote>> basket;
    basket.push_back(make_shared<Quote>("1233", 50));
    basket.push_back(make_shared<Bulk_Quote>("12", 50, 10, .25));
    cout << basket.back()->net_price() << endl;

### 学习《C++ Primer》- 8的更多相关文章

  1. Python学习--04条件控制与循环结构

    Python学习--04条件控制与循环结构 条件控制 在Python程序中,用if语句实现条件控制. 语法格式: if <条件判断1>: <执行1> elif <条件判断 ...

  2. Python学习--01入门

    Python学习--01入门 Python是一种解释型.面向对象.动态数据类型的高级程序设计语言.和PHP一样,它是后端开发语言. 如果有C语言.PHP语言.JAVA语言等其中一种语言的基础,学习Py ...

  3. Python 学习小结

    python 学习小结 python 简明教程 1.python 文件 #!/etc/bin/python #coding=utf-8 2.main()函数 if __name__ == '__mai ...

  4. Python学习路径及练手项目合集

    Python学习路径及练手项目合集 https://zhuanlan.zhihu.com/p/23561159

  5. python学习笔记-python程序运行

    小白初学python,写下自己的一些想法.大神请忽略. 安装python编辑器,并配置环境(见http://www.cnblogs.com/lynn-li/p/5885001.html中 python ...

  6. Python学习记录day6

    title: Python学习记录day6 tags: python author: Chinge Yang date: 2016-12-03 --- Python学习记录day6 @(学习)[pyt ...

  7. Python学习记录day5

    title: Python学习记录day5 tags: python author: Chinge Yang date: 2016-11-26 --- 1.多层装饰器 多层装饰器的原理是,装饰器装饰函 ...

  8. [Python] 学习资料汇总

    Python是一种面向对象的解释性的计算机程序设计语言,也是一种功能强大且完善的通用型语言,已经有十多年的发展历史,成熟且稳定.Python 具有脚本语言中最丰富和强大的类库,足以支持绝大多数日常应用 ...

  9. Python学习之路【目录】

    本系列博文包含 Python基础.前端开发.Web框架.缓存以及队列等,希望可以给正在学习编程的童鞋提供一点帮助!!! 目录: Python学习[第一篇]python简介 Python学习[第二篇]p ...

  10. python学习笔记系列----(八)python常用的标准库

    终于学到了python手册的最后一部分:常用标准库.这部分内容主要就是介绍了一些基础的常用的基础库,可以大概了解下,在以后真正使用的时候也能想起来再拿出来用. 8.1 操作系统接口模块:OS OS模块 ...

随机推荐

  1. 第十一章、认识与学习 BASH 管线命令 (pipe)

    管线命令使用『 | 』界定符号 [root@www ~]# ls -al /etc | less 管线命令『 | 』仅能处理经由前面一个命令传来的正确信息,也就是 standard output 的信 ...

  2. hdu 5505 GT and numbers

    GT and numbers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

  3. 【Stage3D学习笔记续】山寨Starling(三):Starling核心渲染流程

    这篇文章我们剔除Starling的Touch事件体系和动画体系,专门来看看Starling中的渲染流程实现,以及其搭建的显示列表结构. 由于Starling是模仿Flash的原生显示列表,所以我们可以 ...

  4. Oracle- 备份单表结构和单表数据

    在网上看到,有用,记录如下: 这是Oracle的备份表结构和数据,因为实际工作对表进行大规模的数据改动都要讲数据进行备份,否则丢了数据那是很头疼的事情. --创建一份表结构 create table ...

  5. [置顶] Objective-C ,ios,iphone开发基础:protocol 协议(委托,代理)的声明

    协议是为了弥补Objective-c中类只能单继承的缺陷,在Objective-c2.0之前当一个类遵循一个协议的时候,必须在类中实现协议的所有方法,在Objective-c2.0之后协议中的方法就有 ...

  6. 重金悬赏的微软:提交Win8漏洞以及发布Win8应用

    随着Windows 8.1这个饱受诟病的操作系统的推出,微软想一举改变颓势,也只有从用户体验上下手了. 近来,微软针对Windows 8.1的漏洞,推出了三项奖励措施: 1.对于发现关键性漏洞,并且这 ...

  7. 好记心不如烂笔头,ssh登录 The authenticity of host 192.168.0.xxx can't be established. 的问题

    用ssh登录一个机器(换过ip地址),提示输入yes后,屏幕不断出现y,只有按ctrl + c结束 错误是:The authenticity of host 192.168.0.xxx can't b ...

  8. Tomcat服务器常用配置和HTTP简介

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...

  9. cocos2d-x 聊天输入框实现

    转自:http://bbs.9ria.com/thread-216948-1-10.html 聊天输入框  (单行输入框 ,多行可自己扩展) 实现功能: 1.普通输入 2.设置输入框显示最大宽度(PT ...

  10. UIView的Touch事件UIControlEvents详解

    首先,UIControlEvents有这个几种: UIControlEventTouchDown = << , // on all touch downs UIControlEventTo ...