【足迹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虚函数
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(【派生类中的虚函数)
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
覆盖的函数必须在有继承关系的不同的类中
(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; //覆盖纯虚函数
};
版权声明:本文博客原创文章,博客,未经同意,不得转载。
【足迹C++primer】52、,转换和继承虚函数相关推荐
- 继承虚函数单层需继承的内存图(VC6.0)
上班之余抽点时间出来写写博文,希望对新接触的朋友有帮助.今天在这里和大家一起学习一下继承虚函数 继承关系图 class A {virtual aa(){}; };class B : public vi ...
- 虚函数继承与虚函数表-汇编码分析
(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu) 参考:https://www.equestionanswers.com/cpp/vptr-and-vta ...
- 菱形继承,多继承,虚继承、虚表的内存结构全面剖析(逆向分析基础)
// 声明:以下代码均在Win32_Sp3 VC6.0_DEBUG版中调试通过.. 在逆向还原代码的时候,必须得掌握了菱形继承,多继承,虚继承虚函数的内存虚表结构.所以,这篇文章献给正在学习C++ ...
- 虚函数 虚继承 抽象类
虚函数.纯虚函数.虚基类.抽象类.虚函数继承.虚继承 虚函数:虚函数是C++中用于实现多态(polymorphism)的机制.核心理念就是通过基类访问派生类定义的函数.是C++中多态性的一个重要体现, ...
- 【虚基类、虚函数及应用】
虚基类 1.虚基类存在的意义 当在多条继承路径上有一个公共的基类,在这些路径中的某几条汇合处,这个公共的基类就会产生多个实例(或多个副本),若只想保存这个基类的一个实例,可以将这个公共基类说明为虚基类 ...
- C++学习笔记——虚函数
2019独角兽企业重金招聘Python工程师标准>>> 基本概念 虚函数是在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数,用法格式为: virtual ...
- 【C++基础之十一】虚函数的用法
虚函数的作用和意义,就不进行说明了,这里主要讨论下虚函数的用法. 1.典型的虚函数用法 可以看到,只有标识为virtual的函数才会产生多态的效果,而且是编译多态.它只能借助指针或者引用来达到多态的效 ...
- c++primer 笔记03多重继承与虚继承
18.3多重继承与虚继承 多个直接基类中产生派生类的能力,多重继承的派生类继承了所有父类的属性 18.3.1多重继承 派生类的派生列表中可以包含多个基类,但这些类不能是final的 class Zoo ...
- 详解虚函数的实现过程之菱形继承(5)
大家看到标题,会不会菱形继承的虚表会不会是重复的呢?祖父类的虚表会不会在子类会不会是两份相同呢?那么我们一起来探索一下吧,冲冲冲!! 首先我们来分析一下: 它一共定义了四个类,分别为CFurnitur ...
最新文章
- 公众号 关注_微信公众号关注图文跳转网页如何操作实现?
- Linux下ps -ef和ps aux的区别及格式详解
- tzwhere模块 根据经纬度判断时区
- ABAP 选择屏幕上添加按钮,按钮上添加文字和图片
- 欠122亿乐视能不能“真还”?数据拆解乐视债务账单
- Win8 官方培训课程
- java编写k线_用Java绘制K线 (转)
- C语言实现线性动态(单向)链表【详细步骤】
- AAAI 2020 Oral | 华科提出TANet:提升点云3D目标检测的稳健性
- 解决springmvc报No converter found for return value of type: class java.util.ArrayList问题
- ACM-ICPC 2018 沈阳赛区网络预赛 B Call of Accepted(表达式求值)
- Cadence系列之SIPI仿真笔记:Cadence多种版本的安装、卸载重装(一)
- JAVA——电子商城三级分类目录查询-递归树形数据结构
- RDDs, Spark Memory, and Execution
- 学习“基于深度学习的故障诊断”开源
- css固定定位的代码,CSS——相对定位、绝对定位、固定定位(示例代码)
- uva_10066	The Twin Towers
- gentoo linux 内核,手动升级Gentoo及其内核的方法
- LCD液晶屏驱动详解
- 基于单链表快排的优化算法
热门文章
- 最小生成树练习1(克鲁斯卡尔算法Kruskal)
- pom.xml的配置详解
- css3高级和低级样式属性先后顺序
- 撰写论文时word使用技巧(转)
- Windows Mobile,用C#更改网络连接(SSID、IP Address、Subnet Mask、Gatew... (转)
- c语言支持默认参数吗,嵌入式C语言可以带“默认参数”的函数吗
- Linux中内联函数,Windows 7上的内联函数的doParallel问题(适用于Linux)
- 安卓APP_ 控件(8)—— AlertDialog
- 全国计算机等级考试题库二级C操作题100套(第96套)
- 修改java启动参数_如何修改jvm启动参数