《C++Primer》14、15章
第14章 重载运算符与类型转换
14.1 基本概念
只有当操作的含义对于用户来说清晰明了时才使用运算符。
选择作为成员还是非成员?
赋值、下标、调用和成员访问运算符必须是成员。
复合赋值运算符一般是成员。
改变对象状态或者与给定类型密切相关的,如递增、解引用通常是成员。
具有对称性的运算符可能转换任意一端元素的运算对象,例如算数、相等、关系和位运算等,通常是非成员函数。
14.2 输入输出运算符(略)
14.3 算术与关系运算符(略)
14.4 赋值运算符(略)
14.5 下标运算符
通常会定义两个版本:一个返回普通引用,一个返回常量引用。
class StrVec{
public:
std::string& operator[](std:size_t n)
{return elements[n];}
const std::string& operator[](std::size_t n) const
{return elements[n];}
private:
std::string *elements;
}
StrVec svec(10);
svec[0] = “zero”;
14.6 递增和递减运算符
区分前置和后置运算符
后置定义时加上(int)
为了与内置版本保持一致,前置运算符应该返回递增或递减后对象的引用。
后置运算符应该返回对象的原值。
解释了有哪些是生成右值?
14.7 成员访问运算符(略)
14.8 函数调用运算符
如果类定义了调用运算符,则该类的对象称为函数对象。
实验:函数调用运算符必须是非静态成员函数
函数调用运算符适用于对象的名称,而不是函数的名称。 |
14.8.1 lambda是函数对象
当我们编写一个lambda后,编译器将该表达式翻译成一个未命名的类的未命名对象。该类中包含一个重载的函数调用运算符。
14.8.2 标准库定义的函数对象
plus<Type>
less<Type>
equal_to<Type>
在算法中使用标准库函数对象:
比如
vector<string> svec;
sort(svec.begin(), svec.end(), greater<string>());
14.8.3 可调用对象与function
普通函数
int add(int i, int j) {return i + j;}
lambda
auto mod = [] (int i, int j) {return i%j};
函数对象类
struct divide {
int operater()(int denominator, int divisor) {
return denominator /divisor;
}
};
标准库function类型:function<int(int,int)> 它表示接受两个int、返回一个int的可调用对象。
function<int(int,int)> f1 = add;
function<int(int,int)> f2 = divide();
function<int(int,int)> f3 = [](int j,int i){return j*i;};
5种可调用对象,完善函数指纹的不能完成的
map<string, function<int(int,int)>>binops = {
{“+”, add},
{“-”, std::minus<int>()},
{“/”, divide()},
{“*”, [](int i, int j){return i*j;}},
{“%”, mod}
};
14.9 重载、类型转换与运算符
显示的类型转换运算符
为了防止异常情况的发生,C++11引入了显示的类型转换运算符(explicit conversion operator)
class SmallInt {
public:
SmallInt(int i =0):val (i)
{
}
explicit operator int() const { return val;}
private:
std::size_t val;
};
当表达式如下时,显示的类型转换将被隐式地执行:
if、while、do、for语句的条件表达式、逻辑运算、条件运算符
第15章 面向对象程序设计
15.1 OOP:概述
面向对象程序设计的核心思想:数据抽象、继承和动态绑定。
数据抽象:可以将类的接口和实现分离;
继承:相似性的类、相似性关系建模;
动态绑定:忽略相似性类的区别,以统一的方式使用对象。
虚函数:希望它的派生类各自定义适合自己的版本。
class Quote{
public:
string isbn() const;
virtual double net_price(std::size_t n) const;
};
class Bulk_quote: public Quote{
public:
double net_price(std::size_t n) const override;
};
动态绑定(运行时绑定):当我们使用基类的引用或指针调用一个虚函数时将发送动态绑定。
每个类负责定义各自的接口,要想与类的对象交互必须使用该类的接口。
防止继承的发生
class NoDerived final {};
15.2 定义基类和派生类
类型转换:
从派生类向基类的转换只对指针或引用类型有效;
基类向派生类不存在隐式类型转换(不怕出问题的显示强制转换是可以的);
15.3 虚函数
基类希望其派生类进行覆盖的函数。
override和final的作用
15.4 抽象基类
纯虚函数:无需定义。函数声明处最后=0。
class exp{
public:
double net_price(std::size_t) const = 0;
};
含有(或者未经覆盖直接继承)纯虚函数的类称为抽象基类。抽象基类负责定义接口。不能创建抽象基类的对象。
15.5 访问控制和继承
每个类负责控制自己的成员的访问控制。有元关系不能传递,也不能继承。
struct D1:Base{}; // 默认public继承
class D2:Base{}; //默认private继承
struct和class唯一区别:默认成员访问说明符和默认派生访问说明符。
15.6 继承中的类作用域
在编译时进行名字查找。
除了覆盖继承而来的虚函数之外,派生类最好不要重用其他定义的基类中的名字。
名字查找先于类型检查。如果派生类的成员和基类的某个成员同名,则派生类将在其作用域内隐藏该基类成员。所以要么重载所有基类的某类函数,要么一个也不覆盖。
15.7 构造函数和拷贝控制
派生类中的创建、拷贝、移动、赋值、销毁。
15.7.1 虚析构函数
将基类的析构函数设置为虚函数,确保当我们delete基类指针时将运行正确的析构函数。
15.7.2 合成拷贝控制与继承
基类因为定义了析构函数而不能拥有合成的移动操作,因此当我们移动基类时,实际运行的是基类的拷贝操作。基类没有移动,意味着派生类也没有移动操作。
但是可以在基类中显示的定义移动、拷贝操作。
15.7.3 派生类的拷贝控制成员
派生类的析构函数只负责派生类自己分配的资源。派生类的构造和移动需要负责包括基类部分成员部分。
class Base{};
Base &Base::operator=(const Base&){
//...
return *this;
};
class D:public Base{
public:
D(const D& d):Base(d){};
D(&& d):Base(std::move(d)){};
};
D &D::operater=(const D&rhs)
{
Base::operater=(rhs);
//...
return *this;
}
如果想在派生类中拷贝和移动基类部分,则必须在派生类的构造函数初始值列表中显示的使用基类的拷贝构造函数。
15.8 容器与继承
当派生类对象被赋值给基类对象时,其中的派生类部分将被切掉,因此容器和存在继承关系的类型无法兼容。
解决办法:在容器中放置(智能)指针而非对象。
例子:
vector<shared_ptr<Quote>> basket;
basket.push_back(make_shared<Quote>(“123-3344”,2));
basket.push_back(make_shared<Bulk_quote>(“234-344”,50));
转载于:https://www.cnblogs.com/sunnypoem/p/9537552.html
《C++Primer》14、15章相关推荐
- C++Primer 第15章 OOP
C++Primer 第15章 OOP #include<iostream> class Base {public:virtual void fun1(int i = 0){std::cou ...
- 【C++ Primer 第15章】定义派生类拷贝构造函数、赋值运算符
学习资料 • 派生类的赋值运算符/赋值构造函数也必须处理它的基类成员的赋值 • C++ 基类构造函数带参数的继承方式及派生类的初始化 定义拷贝构造函数 [注意]对派生类进行拷贝构造时,如果想让基类的成 ...
- 【传智播客】Javaweb程序设计任务教程 黑马程序员 第7,8,9,10,11,12,13,14,15章 课后答案
所有章节答案合集-->传送门 第一部分是题目,向下翻, 第二部分是答案 第七章 [测一测] 学习完前面的内容,下面来动手测一测吧,请思考以下问题: 1.简述Javabean规范都有哪些?(至少写 ...
- C++ primer 第15章 面向对象程序设计
文章目录 前言 OOP:概述 继承 动态绑定 定义基类和派生类 定义基类 成员函数与继承 访问控制与继承 定义派生类 派生类中的虚函数 派生类对象及派生类向基类的类型转换 派生类构造函数 派生类使用基 ...
- MATLAB神经网络43个案例分析【第14/15章源程序不能正常运行——一种道听途说的解决办法】
鄙人在下载并运行<MATLAB神经网络43个案例分析>随书附带的源程序时发现,chapter14文件夹中的chapter_WineClass.m文件并不能正常运行.命令行窗口出现了如下警告 ...
- 阅读第13,14,15,16,17章
13章:效能测试 不一样的机器运行软件效率是不一样的,怎么能做到效能测试的权威性 14章:软件质量保障 这是一个很重要的问题,国外公司很注重维护,中国公司也注重更新维护吗? 15章:稳定和发布阶段 软 ...
- 读书笔记_代码大全_第14章_组织直线型代码_第15章_使用条件语句
组织直线型代码 + 使用条件语句 希望我的读书笔试能带你翻过18页的书 http://www.cnblogs.com/jerry19880126/ <代码大全>第14章和第15章的内容比较 ...
- 《C++ Primer》第15章 15.4节习题答案
<C++ Primer>第15章 面向对象程序设计 15.4节 抽象基类 习题答案 练习15.15:定义你自己的Disc_quote和Bulk_quote. [出题思路]本题练习实现不同折 ...
- 《C++ Primer》第15章 15.2节习题答案
<C++ Primer>第15章 面向对象程序设计 本章介绍了面向对象程序设计的两个重要概念:继承和动态绑定,包括: □●继承.基类.派生类的基本概念. □●虚函数和虚基类. □●继承中的 ...
最新文章
- 程序员眼中的英文单词是这样的
- wegame饥荒一直连接中_23万人捧场热血传奇怀旧版,WeGame拯救计划,前景如何?...
- 使用苹果版博客编辑器发布的文章
- 编程语言python特点-十种常用编程语言特点
- Android程序杀死自己的进程和其他程序进程方法
- 常见排序算法的C#实现
- mysql的程序怎么升级成mysqli_如何将mysql更改为mysqli?-问答-阿里云开发者社区-阿里云...
- 写SQL语句需要注意的点
- svn服务器地址更改
- bash: go: 未找到命令_golang快速入门[2.3]-go语言开发环境配置-linux
- Linux 进程间通讯(IPC)方式 ------- 共享内存
- SQL注入实验,PHP连接数据库,Mysql查看binlog,PreparedStatement,mysqli, PDO
- RTP协议RTCP协议
- liunx 系统下面安装jdk
- 能卷死同行的收银系统源码--连锁门店/美业/订货/saas/java/php
- 京东个人注册开店要怎么做?京东开店步骤介绍!
- Android 设置APP桌面图标
- 炎颂科技管理系统软件——助力商协会“互联网+”之路
- USB3.0:VL817Q7-C0的LAYOUT指南(二)
- 初学者用Eclipse和IDEA哪个好用一点?
热门文章
- 如何共享计算机磁盘,扩展群集共享磁盘的分区 - Windows Server | Microsoft Docs
- python字典的键设置条件格式_openpyxl条件格式设置数字格式
- java求sin函数咋写_5类“隐含条件”,题干不写但是你要会用(解三角形知识整合,建议收藏)| 真题精讲-16...
- php项目重构,跪求网页重构、前端开发、PHP 开发,坐标深圳腾讯 CDC
- PHP微信模版消息有时收不到_PHP微信开发之模板消息回复
- 机器学习理论与实战:逻辑回归
- mybatis generator 中文注释_[SpringBoot2.X] 23- 整合持久层技术 -MyBatis - 配置
- 前景检测算法(二)--codebook和平均背景法
- android中的广播机制(动态注册)
- vue 自定义键盘组件_vue 自定义 数字键盘+mint UI MessageBox的应用