《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

时间: 2024-11-09 10:53:56

《C++Primer》14、15章的相关文章

第12 13 14 15章总结与感悟

第12章 用户体验 12.1用户体验的要素 1.1用户的第一印象 1.2从用户的角度考虑问题,这需要“同理心”(理解别人的处境,心理,动机和能力) 用户需要帮助,但是用户没那么笨 光吃狗食也不够 1.3软件服务始终记住用户的选择 1.4短期刺激和长期影响 1.5不让用户犯简单的错误 1.6用户体验和质量 1.7情感设计 12.2用户体验设计的步骤和目标 12.3评价标准 1.尽快提供可感触的反馈 2.系统界面符合用户的现实管理 3.用户有控制权 4.一致性和标准化 5.适合各种类型的用户 6.帮

【C++ Primer 第15章】抽象基类

抽象基类 [注意]我们也可以为纯虚函数提供定义,不过函数体必须在类的外部,也就是说,我们不能再内部为一个=0思网函数提供函数体. C++中含有(或未覆盖直接继承)纯虚函数的类是抽象基类,抽象基类负责定义接口,而后续的的其他类可以覆盖接口.我们不能直接出创建一个抽象基类的对象. C++中的纯虚函数更像是“只提供申明,没有实现”,是对子类的约束,是“接口继承”. C++中的纯虚函数也是一种“运行时多态”. 1 class A 2 { 3 public: 4 virtual void out1(str

c++ primer第15章这几个例子中的构造函数形式不太理解

//向基类构造函数传递实参p491 class Bulk_item : public Item_base{ public: Bulk_item(const std::string& book,double sales_price,std::size_t qty = 0,double disc_rate = 0.0): Item_base(book,sales_price),min_qty(qty),discount(disc_rate){} }; //在派生类构造函数中使用默认实参p491 cl

【【C++ Primer 第15章】 虚析构函数

学习资料 • C++中基类的析构函数为什么要用virtual虚析构函数 虚析构函数 1. 正文 直接的讲,C++中基类采用virtual虚析构函数是为了防止内存泄漏.具体地说,如果派生类中申请了内存空间,并在其析构函数中对这些内存空间进行释放.假设基类中采用的是非虚析构函数,当删除基类指针指向的派生类对象时就不会触发动态绑定,因而只会调用基类的析构函数,而不会调用派生类的析构函数.那么在这种情况下,派生类中申请的空间就得不到释放从而产生内存泄漏.所以,为了防止这种情况的发生,C++中基类的析构函

C++ Primer Plus 第15章 友元、异常和其他

第15章 友元.异常和其他 1.友元不仅有友元函数,还能是友元类 还可以将类中的某一个成员函数指定为另一个类的友元 尽管友元被授予从外部访问私有部门的权限,单并不与面向对象编程思想相愽,相反,它们提高了公有接口的灵活性 2.类的成员函数作为其他类的友元,涉及到类的声明顺序. 还有一个函数作为两个类的友元 这方面内容看P607-611 3.嵌套类:在另一个类中声明的类被称为嵌套类 类嵌套与包含不一样.包含意味着将一个类对象作为另一个类的成员,而对类进行嵌套不创建类成员,而是定义了一种类型. 4.对

《构建之法》13,14,15,16,17章读后感

1.13章说的是软件测试,怎么样去测试是最有效率的? 2.14章说到质量保障,具体的花费是多少? 3.15章说到ZBB,如果一个软件遇到了不可修复的bug,还算是一个稳定的软件么? 4.16章说到创新,有实际例子吗? 5.17章的职业道德指的是什么?

3.30日第八次作业,第14章,采购管理,15章,信息文档和配置管理

3.30日第八次作业,第14章,采购管理,15章,信息文档和配置管理   第14章.采购管理1.采购管理包括哪些过程?(记)P382-383 答:1).编制采购计划.2).编制询价计划.3).询价.招投标.4).供方选择.5).合同管理.6).合同收尾. 2.编制采购计划过程的成果是什么?P386-387 答:1).采购管理计划.2).采购工作说明书. 3.判断:每个采购工作说明书都来自于项目范围基准.P387 答:是的. 4.结合P388页表14-1,工作说明书应该清楚地描述哪些内容?P388

阅读第13,14,15,16,17章

13章:效能测试 不一样的机器运行软件效率是不一样的,怎么能做到效能测试的权威性 14章:软件质量保障 这是一个很重要的问题,国外公司很注重维护,中国公司也注重更新维护吗? 15章:稳定和发布阶段 软件发布后,逐步冻结为什么要从人机界面开始冻结 16章 IT行业的创新 创新者都是一马当先,为什么美国易贝网站最先在互联网世界提出用户对用户交易平台,然而在中国却基本听不懂易贝交易平台 17章 读一个程序猿的生命周期 这让我懂得人生不管干什么方向很重要,更重要的是要手上有实力

Java面向对象程序设计第14章3-8和第15章6

Java面向对象程序设计第14章3-8和第15章6 3.完成下面方法中的代码,要求建立一个缓冲区,将字节输入流中的内容转为字符串. import java.io.*; public class test { static String loadStream(InputStream in) throws IOException { StringBuffer buffer = new StringBuffer(); int count= 1,i=6; byte[] buf = new byte[co