C++ Primer12抽象基类

继续昨天的

类型转换与继承

我们可以将基类的指针和引用绑定到派生类对象上。当使用基类的引用或指针时,实际上我们并不清楚我们使用的对象到底是基类对象还是派生类对象。

静态类型和动态类型

例如item.net_price(),它的静态类型是Quote&,动态类型则根据传入的实参来决定。如果传入的是Bulk_quote,则动态类型为Bulk_quote。

如果表达式既不是引用也不是指针,则它的动态类型永远与静态类型一致。

不存在从基类向派生类的隐式类型转换。

派生类对象之所以可以绑定到基类的指针和引用上,是因为派生类包含基类部分,基类的指针和引用可以绑定到该基类部分。而反过来则不行。

注意了!这句话很重要!

在对象之间不存在类型转换,派生类向基类的转换只对指针和引用有效,在派生类类型和基类类型之间不存在这样的转换。

如果我们用一个派生类对象初始化或者赋值一个基类对象会发生什么?

Bulk_quote bulk;
Quote item(bulk);//拷贝构造函数 Quote(const Quote&)
item = bulk;//拷贝赋值运算符 Quote& operator=(const Quote&)

这样做是可以的,但是这样做我们只能处理基类部分的成员,派生类部分的成员会被切掉。

也就是下面这句话:
当我们用一个派生类对象为一个基类对象初始化或赋值时,只有派生类对象中的基类部分会被拷贝、移动或赋值,它的派生类部分会被忽略掉。

虚函数

当我们使用基类的引用或指针调用一个虚函数时会发生动态绑定。
因为我们直到运行时才能知道到底调用了哪个版本的虚函数,所以所有虚函数都必须有定义。
当某个虚函数通过指针或引用调用时,编译器产生的代码直到运行时才能确定应该调用哪个版本的虚函数。被调用的函数是与绑定到指针和引用上的对象的动态类型相匹配的那个。

经典语录:
当且仅当对通过指针或者引用调用的虚函数时,才会在运行时解析该调用,也只有在这种情况下对象的动态类型才有可能与静态类型不同。


派生类中的虚函数
一旦某个函数被声明成了虚函数,则在所有派生类中它都是虚函数。

一个派生类的函数如果覆盖了某个继承而来的虚函数,则它的形参类型和返回值必须与基类类型完全一致。override只用来检查这种一致性的。

虚函数与默认实参
如果我们使用基类的引用或指针调用函数,则使用基类中定义的默认实参,即使实际运行的是派生类中的函数版本。所以实际编程中,基类和派生类中定义的默认实参最好一致。

抽象基类

含有纯虚函数的类为抽象基类,抽象基类充当了一种接口的作用。
比如说下面的Disc_quote类,它用来存储购买数量和折扣,然后为它的派生类们提供接口net_price()。我们不希望定义这个类的对象,因为它只是用来存储数据以及提供接口的。
一个类如果有纯虚函数则不能定义这个类的对象。
抽象基类的作用好像就像是把数据从各个类中提取出来一样。,如果一个类没有覆盖纯虚函数,则它依然是一个抽象基类。

抽象基类Disc_quote:

#pragma once
#include "Quote.h"
using namespace std;
class Disc_quote : public Quote
{
public:
	Disc_quote() = default;
	Disc_quote(const string& s, double sales_price, double dis, size_t qua) :
		Quote(s, sales_price), discount(dis), quantity(qua){}
	virtual double net_price(size_t n) const = 0;
	virtual void debug() const = 0;
protected:
	double discount;
	size_t quantity;
};

其他类几乎没有变动。

友元与继承
就像友元关系不能传递一样,友元关系同样也不能继承

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

改变个别成员的可访问性

有时我们需要改变派生类继承的某个名字的访问级别,通过使用using声明可以做到这一点。

#pragma once
using namespace std;
class Base
{
public:
	size_t size() const
	{
		return n;
	}
protected:
	size_t n;
};
#pragma once
#include"Base.h"
using namespace std;
class Derived : private Base
{
public:
	using Base::size;
protected:
	using Base::n;
};

默认继承方式

用class定义的类,默认继承方式为private
用struct定义的类,默认继承方式为public

这次就到这儿吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值