【足迹C++primer】52、,转换和继承虚函数

转换和继承,虚函数


Understanding conversions between base and derived classes is essential to
understanding how object-oriented programming works in C++.
理解基类和派生类之间的转换是不可缺少的 理解面向对象编程在。


Like built-in pointers, the smart pointer classes (§12.1, p. 450) support the
derived-to-base conversion—we can store a pointer to a derived object in a
smart pointer to the base type.


像内置指针,智能指针类支持 导出到基类的转换能够存储一个指向派生类对象的一个
基类类型的指针。


Static Type and Dynamic Type(静态和动态类型)

class Quote
{
public:Quote()=default;Quote(const string &book, double sales_price):bookNo(book), price(sales_price){cout<<"Quote gouzhao function"<<endl;}string isbn() const {return bookNo;}//返回指定数量的项目总销售价格//派生类将重写应用不同的折扣算法virtual double net_price(size_t n) const {return n*price;}virtual ~Quote()=default;   //动态链接析构函数
private:string bookNo;  //这本书的isbn号
protected:double price=0.0;       //不打折的价格};//继承,怎样继承?
class Bulk_quote : public Quote
{
public:Bulk_quote()=default;Bulk_quote(const string & book, double p, size_t qty, double disc): Quote(book, p), min_qty(qty), discount(disc){cout<<"Bulk_quote construct function"<<endl;}//重写虚函数double net_price(size_t n) const override {cout<<"double net_price(size_t)"<<endl; return n*price;}//再次说明,请声明函数后一定要记得定义它。不然我这是出了各种莫名其妙的错误!
//    ~Bulk_quote2(){cout<<"~Bulk_quote2()"<<endl;}
private:size_t min_qty=0;double discount=0.0;
};

There Is No Implicit Conversion from Base to Derived ...

void fun1()
{Quote base;
//    Bulk_quote* bulkP=&base;    错误不能把基类转换成派生类
//    Bulk_quote& bulkRef=base;    同上Bulk_quote bulk;Quote *itemP=&bulk;     //派生类转换成基类
//    Bulk_quote *bulkP=itemP;    error:基类到派生类
}

...and No Conversion between Objects

void fun2()
{Bulk_quote bulk;    //派生类Quote item(bulk);   //调用基类Quote的赋值构造函数item=bulk;          // calls Quote::operator=(const Quote&)拷贝赋值运算符
}

这里当我们的參数对象是基类的时候。转换的时候仅仅有基类部分会被拷贝。而派生的那部分
会直接被忽略

Virtual Functions虚函数

Key Concept: Conversions among Types Related by Inheritance
There are three things that are important to understand about conversions
among classes related by inheritance:
• The conversion from derived to base applies only to pointer or reference
types.
• There is no implicit conversion from the base-class type to the derived
type.
• Like any member, the derived-to-base conversion may be inaccessible due
to access controls.
关键概念:继承关系的类型之间的转换
因继承而相关联的类中转换的重要的三件事 :
•从派生类到基类的转换仅仅适用于指针或引用 类型。
•有从基类到派生类没有隐式转换
•像不论什么成员,派生类到基类的转换可能无法訪问因为 訪问控制。



动态绑定

double print_total(ostream &os, const Quote &item, size_t n)
{//依据不同的对象来绑定到这个參数的类型//这里引用Quote::net_price 或 Bulk_quote::net_pricedouble ret=item.net_price(n);os<<"ISBN: "<<item.isbn()   //调用 Quote::isbn<<" # sold: "<<n<<" total due: "<<ret<<endl;return ret;     //这里上面的Quote參数是能够接受Quote或者Bulk_quote类型的
}

Calls to Virtual Functions May Be Resolved at Run Time
调用的虚函数能够在执行时确定

void fun3()
{Quote base("0-201-82470-1", 50);print_total(cout, base, 10);    //调用Quote的net_priceBulk_quote derived("0-201-82470-1", 50, 5, 0.19);print_total(cout, derived, 10); //调用Bulk_quote的net_pricebase=derived;   //吧quote类型的部分复制到basebase.net_price(20);
}

Virtual Functions in a Derived Class(【派生类中的虚函数)

A function that is virtual in a base class is implicitly virtual in its
derived classes. When a derived class overrides a virtual, the parameters in
the base and derived classes must match exactly.

The final and override Specifiers

(1)       重载的几个函数必须在同一个类中。
覆盖的函数必须在有继承关系的不同的类中
(2)       覆盖的几个函数必须函数名、參数、返回值都同样;
重载的函数必须函数名同样,參数不同。參数不同的目的就是为了在函数调用的时候编译器可以通过參数来推断程序是在调用的哪个函数。

这也就非常自然地解释了为什么函数不能通过返回值不同来重载。由于程序在调用函数时非常有可能不关心返回值,编译器就无法从代码中看出程序在调用的是哪个函数了。


(3)       覆盖的函数前必须加keywordVirtual;
重载和Virtual没有不论什么瓜葛,加不加都不影响重载的运作。



struct B
{virtual void f1(int) const;virtual void f2();void         f3();
};struct D1 : B   //这是什么继承?
{void    f1(int) const   override;   //ok能够覆盖
//    void    f2(int) override;   error没有f2(int)这个虚函数
//    void    f3()    override;      //error:f3()不是虚函数
//    void    f4()    override;       error:没有f4()这个虚函数
};

final这个keyword

struct D2 : B
{//从B继承f2,f3之后我们override f1void f1(int) const final;   //之后派生类无法覆盖f1
};struct D3 : D2
{void f2();
//    void f1(int) const; //注意:这个函数是被final修饰的函数
};

Virtual Functions and Default Arguments(虚函数和默认參数)

具有默认參数的虚函数应该使用同样的參数 在基值和派生类。



Circumventing the Virtual Mechanism

void fun4()
{cout<<"there is fun4"<<endl;Quote *baseP;double undiscounted = baseP->Quote::net_price(42);
}

Ordinarily, only code inside member functions (or friends) should need to use
the scope operator to circumvent the virtual mechanism
通常仅仅有类里面的成员函数(友元函数)须要使用作用域操作符来规避虚拟机制

15.4. Abstract Base Classes

抽象类就是类里定义了纯虚成员函数的类


为什么要定义抽象基类呢?依我所见主要有下面原因:
1.最重要的原因是,能够将接口与实现分离。

接口是软件产品最有价值的资源。
设计接口比实现接口须要耗费更昂贵的成本。

因此,要将接口保护起来,
以免在针对客户需求改动实现的时候,程序猿不小心把接口破坏掉。
2.引入抽象基类和纯虚函数方便实现C++的多态特性。
能够用抽象基类的指针去调用子类对象的方法。
3.非常多时候。很多基类被实例化是不合理的。
比如“形状”这个基类,被实例化之后反而会让人相当费解,
所以干脆将“形状”这个类定义为抽象类,由它派生出正方形,三角形等子类。


纯虚函数

当类声明中包括纯虚函数时。则不能创建该类的对象。


基类的纯虚函数必须有“=0”,但不一定没有函数的实现,仅仅是不能直接内嵌在类中。



class Disc_quote : public Quote
{
public:Disc_quote()=default;Disc_quote(const string & book, double price, size_t qty, double disc):Quote(book, price), quantity(qty), discount(disc) {cout<<"Disc_quote构造函数"<<endl;}double net_price(size_t) const = 0; //纯虚函数
protected:size_t quantity=0;double discount=0.0;
};

纯虚函数不能直接在类里面进行定义。要定义就要在外面
virtual void Move(int nx, int ny) = 0;
void BaseEllipse::Move(int nx, int ny) {x = nx; y = ny;}
这样是同意的

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

void fun5()
{cout<<"there is fun5"<<endl;
//    Disc_quote discount;    //error:Disc_quote是一个抽象类,含有纯虚函数没法实例化Bulk_quote bulk;        //ok,这个里面没有纯虚函数,不是抽象类
}

A Derived Class Constructor Initializes Its Direct Base Class Only
就是派生类參数列表能够直接初始化基类

class Bulk_quote2 : public Disc_quote
{
public:Bulk_quote2()=default;//直接初始化Bulk_quote2(const string& book, double price, size_t qty, double disc):Disc_quote(book, price, qty, disc) {}double net_price(size_t) const override;    //覆盖纯虚函数
};





有些人认为,做人要真,所以说话要直。结果就到处直来直去得罪人。事实上大错。中国人写"真"字,是"直"以下两点。也就是说,一些实话、直话,也要保留两点。不要所有说出去。实话实说是真,但实话全说就是蠢。肚子里藏不住话的人,自以为说真话。事实上只是是情商不够而已。

不幸的是,作者好像既不真也不直~~~~~大哭哭


版权声明:本文博客原创文章,博客,未经同意,不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/288432.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

聊一聊Redis的离线分析

背景 Redis 或许是我们大部分场景都会用到的一个利器&#xff0c;虽然是利器&#xff0c;用的姿势不对的话&#xff0c;终究还是会整出幺蛾子的。比较常见的问题&#xff0c;不外乎内存暴增&#xff0c;慢查询等情况。那么对于内存问题&#xff0c;可以借助redis自带的bigkey分…

虚拟机VMware安装XP系统错误解决办法

虚拟机给我的编程工作确实带了很多方便&#xff0c;但是虚拟机的一个最大挑战是硬件赶不上&#xff0c;速度太慢了。最近一直在致力于虚拟机上Win7专业版平台上SQL Server 2005Visual Studio 2012系统开发&#xff0c;最初还可以&#xff0c;但是越到后面速度越慢。最后决定重新…

【Python】猜数小游戏(文件操作)

人生苦短&#xff0c;我用Python 关键词 1.多用户 2.字典记录所有成绩 3.每次游戏轮数&总游戏次数&平均每次游戏需要多少轮 字典Dictionary、列表List、元组Tuple差异化理解 from random import randintname input(请输入你的名字&#xff1a;)#输入玩家名字 #读取文件…

100ms的SQL把服务器搞崩溃了

前言一个项目上线了两个月&#xff0c;除了一些反馈的优化和小Bug之外&#xff0c;项目一切顺利&#xff1b;前期是属于推广阶段&#xff0c;可能使用人员没那么多&#xff0c;当然对于项目部署肯定提前想到并发量了&#xff0c;所以早就把集群安排上&#xff0c;而且还在测试环…

需求分析工程师岗位的职责描述(合集)

需求分析工程师岗位的职责描述1 职责&#xff1a; 1&#xff0c;负责需求调研&#xff0c;对需求进行分析&#xff0c;编写解决方案、需求规格说明书等 2&#xff0c;根据需求制作原型&#xff0c;并负责原型展示以及客户沟通等工作 3&#xff0c;负责向技术团队精确地传达业务…

nginx 下配置使用Thinkphp5解决跨目录活动并且设置网站根目录

由于TP5框架的一些特性规则&#xff0c;在nginx下导致跨目录的一些访问不能执行 最开始我尝试配置文件夹目录&#xff0c;导致出现各种奇葩错误&#xff0c;然后搜了以下资料发现原来只要简单的修改几个配置文件即可。 声明系统环境&#xff1a; **系统&#xff1a;Centos6.版本…

如何使用CPU来加速你的Linux命令

我们都知道 grep, bzip2, wc, awk, sed等等&#xff0c;都是单线程的&#xff0c;只能使用一个CPU内核。那么如何才能使用这些内核? 要想让Linux命令使用所有的CPU内核&#xff0c;我们需要用到GNU Parallel命令&#xff0c;它让我们所有的CPU内核在单机内做神奇的map-reduce操…

关于nginx为站点绑定域名以及绑定多个域名

环境&#xff1a; 系统&#xff1a;Centos6.版本 使用lnmp一键安装包安装环境&#xff08;配置文件地址在其官网有写&#xff09; 找到nginx的conf文件&#xff0c;我的目录为&#xff1a; /usr/local/nginx/conf 随后找到&#xff1a;server_name _; 如果没有配置就是…

【6】JAVA---地址App小软件(QueryPanel.class)(表现层)

查找模块&#xff1a; 年龄可进行段查找。 其他的都是模糊匹配。 空格为无用字符&#xff0c;会屏蔽的&#xff08;除年龄&#xff09;。 &#xff08;如果在年龄中输入空格&#xff0c;会出现异常&#xff0c;当时没想到这点&#xff0c;要防护这点很容易的&#xff0c;但…

Edge 超越 Safari 成为全球第二大桌面端浏览器!Firefox 爆降致 Chrome 份额再创新高!...

桌面端StatCounter 近日发布全球桌面端浏览器 2022 年 3 月统计报告&#xff1a;微软 Microsoft Edge 浏览器桌面端市场份额从 9.61% 上升至 9.65%&#xff0c; 苹果 Safari 浏览器桌面端市场份额从 9.77% 下降至 9.56%。 这也意味着微软 Microsoft Edge 浏览器正式超越苹果 Sa…

hackgame汇总

2019独角兽企业重金招聘Python工程师标准>>> http://www.hackerforever.com/survius.php http://www.funnygames.co.nz/play/hacker http://www.hackerskills.com/ http://www.mod-x.co.uk/whatisit.php http://www.hackerevolution.org/page_hackerevolution.h…

关于thinkphp5的报错 mkdir() Permission denied的解决

声明环境: 系统&#xff1a; Centos 6.8 64x nginx 使用lnmp一键安装包安装 已解决tp5跨目录活动问题 mkdir() 的作用是函数创建目录&#xff0c;即读写相关&#xff0c;那么即报错“permission denied” 则我们可以改变目录权限。 环境为nginx&#xff0c;nginx有设置的访问用…

.NET LoongArch64 正式合并进入.NET

国内自主的龙芯&#xff0c;在做龙芯技术生态就把 .NET 作为其中一部分考虑进去&#xff0c;这也将对接下来国内.NET应用场景充满了期待。通过dotnet/runtime 可以知道现在龙芯版本的 .NET 已经合并到.NET 7 官方分支的工作已经完成了。LoongArch64架构合并进入.NET 7.0 已经安…

qtabwidget切换tab事件_某超超临界机组初压/限压切换过程中扰动原因分析

严寒夕 浙江浙能台州第二发电有限责任公司&#xff3b;摘要&#xff3d;某火电厂汽轮机在初压/限压切换过程中出现负荷瞬时上升问题。从初压/限压切换的逻辑及切换过程中主要参数的变化分析,确定原因为压力控制器指令上升瞬间和转速负荷控制器指令下降瞬间有短暂的时间间隔,造…

WiresShark之抓http包如何倒出图片格式的对象

1 问题 在WireShark抓取http数据包之后,里面有图片链接,我们怎么进行导出来,当然这里在浏览器或者Fiddler里面普通图片格式可以显示出来。 2 举例子操作说明 1)比如我们访问www.hao123.com.cn这个网站,我们首先打开wireShark,开启抓包,然后用浏览器访问这个网站,页面效…

linux生成地图,ROS中利用V-rep进行地图构建仿真

V-rep中显示激光扫描点在VREP自带的场景中找到practicalPathPlanningDemo.ttt文件&#xff0c;删除场景中多余的物体只保留静态的地图。然后在Model browser→components→sensors中找到SICK TiM310 Fast激光雷达&#xff0c;拖入场景中&#xff1a;打开脚本参数修改器&#xf…

Python环境搭建与连接SQL Server类MyDBase的实现

一、开发环境搭建 1、下载所需版本的软件包(点击下载),点击安装即可,注意x86与x64的选择。 2、配置环境:复制python安装目录,粘贴到Path中 3、打开cmd,输入python并回车,看到如下信息,则安装成功!

如何隐藏地址栏中的真实地址_Firefox推出Private Relay插件:可隐藏真实邮箱地址...

Mozilla 正在为 Firefox 开发一项名为Private Relay 的新服务&#xff0c;它能够用来一键随机生成电子邮件别名&#xff0c;以隐藏真实邮箱地址&#xff0c;使用户免受广告商和垃圾邮件侵害。Private Relay 将作为 Firefox插件提供。它于上个月开始测试&#xff0c;目前仍处于封…

使用VS开发C++ 控制台程序或其他项目出现 ‘ LINK : fatal error LNK1104: 无法打开文件“LIBCD.lib” ’ 常规解决办法

原因&#xff1a;大多是由低版本例如VC6(本人是)开发项目&#xff0c;然后在高版本上再开发该项目导致LIBCD.lib出现更改由此出现错误提示。 本人VS版本2017&#xff1b; 一般解决办法&#xff1a; 第一步&#xff1a;右键项目属性 第二步&#xff1a;在忽略特定库位置加上要忽…

不同步节点在线使用Remix开发以太坊Dapp及solidity学习入门 ( 一 ):智能合约HelloWorld

有问题可以点击–>加群互相学习 本人本来想自己写公链&#xff0c;结果发现任重道远&#xff1b; 遂&#xff0c;开始写Dapp&#xff0c;顺便写的时候搞个教程吧。。。 通过系列教程学习将会&#xff1a; 1.基本使用solidity 语言开发智能合约 2.知道怎么发自己的以太坊的to…