// chapter-15.cpp : 继承和动态绑定!
//
#include "stdafx.h"
#include<iostream>
#include<string>
#include<vector>
#include<memory>
using namespace std;
class Quote //报价,基类.
{
public:
Quote() = default;
Quote(const string &book,double sales_price):bookNo(book),price(sales_price){}
string isbn() const { return bookNo; }
virtual double net_price(size_t n) const { return n*price; }//虚函数,希望派生类重定义覆盖!当使用指针或引用调用函数时,将发生动态绑定!
virtual ~Quote() = default; //继承中,根类通常应该定义一个虚析构函数!来保证使用正确的析构函数释放对象!
private:
string bookNo;
protected: //派生类可以访问共有成员,保护成员,不能访问私有成员。类外只能访问共有成员!
double price = 0.0;
};
class Bulk_Quote:public Quote
{
public:
Bulk_Quote() = default; //每个类负责定义各自的接口,想要与类的对象交互必须使用该类的结构。即是派生类初始化时,也必须使用基类的构造函数来初始化那些从基类中继承而来的成员!
Bulk_Quote(const string &book, double sales_price, size_t mq, double ds) :Quote(book,sales_price), min_qty(mq), discount(ds) {}
double net_price(size_t n) const override //override表示覆盖基类中虚函数,如果没覆盖则引发错误!
{
if (n >= min_qty)
return n*(1 - discount)*price;
else
{
return n*price;
}
}
private:
size_t min_qty = 0;
double discount = 0.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){}
double net_price(size_t n) const = 0; //含有纯虚函数的类为抽象基类,后续其他类可以覆盖接口,但是不能创建抽象基类的对象!
protected:
size_t quantity = 0;
double discount = 0;
};
class Bulk_DiscQuote:public Disc_Quote
{
public:
Bulk_DiscQuote() = default;
Bulk_DiscQuote(const string &book, double price, size_t qty, double disc) :Disc_Quote(book, price, qty, disc) {}
double net_price(size_t n) const override;
};
double Bulk_DiscQuote::net_price(size_t n) const
{
if (n >= quantity)
return n*(1 - discount)*price;
else
{
return n*price;
}
}
class Base
{
public:
size_t size()const { return n; }
private:
size_t n;
};
class Pri_Base:public Base
{
public:
using Base::size; //通过using声明,改变成员的可访问性!
private:
//using Base::n;
};
int main()
{
//根部为基类,从基类继承的为派生类。基类负责定义层次关系中所有类共同拥有的成员,而派生类定义各自特有的成员!
//在基类中声明函数,在各自派生类中定义适合自身的版本,此时基类就将这些函数声明为虚函数!在运行中,实际执行的虚函数版本将由派生类对象而定,即为动态绑定!
Quote qb1("c++", 150);
Bulk_Quote qb2("c++", 150,1,0.2);
Quote *p = &qb2;
Quote &r = qb2; //p和r分别指向qb2的Quote部分(派生类向基类转换只针对指针(包括智能指针)和引用,基类向派生类不存在隐式类型转换,根据派生类继承方式而受影响!(1、公有继承!544页)(基类派生类之间不存在对象转换,多余部分会被切除!)
cout << qb1.net_price(4) << " " << qb2.net_price(4) << endl; //动态绑定!
//如果基类中定义了静态成员,则所有继承体系中只存在该成员唯一定义!如果static为private,则派生类无权访问它!
//派生类声明时,不需要派生类表(基类名称),声明形式class Bulk_Quote;、、如果某类为基类,则必须在之前已经声明且定义、、为了防止类被继承,则可以补充声明:class Quote final;
//可以对函数声明final,则继承类所有尝试覆盖操作都是错误的!可以对函数声明override,显示为对基类虚函数的重定义!
//抽象基类,对Quote进行重构,以便将操作和数据移向Bulk_DiscQuote(DiscQuote为抽象基类无法创建对象!)
Bulk_DiscQuote bdq1("c++", 150, 1, 0.2);
cout << bdq1.net_price(4) << endl;
//类成员public、protected、private分别控制继承类是否可以访问;公有、私有、受保护继承分别控制派生类对基类成员的访问权限(更改公有和保护属性的属性值!)
//基类应该将接口声明为公有,将派生类访问声明为保护,将基类和友元访问成员声明为私有!
//友元关系不能继承!不能传递!(对于派生类的友元,可以通过派生类对象访问基类成员!543!对于基类的友元,可以访问基类成员和派生类的基类部分!)
//在继承作用域内,派生类如果定义了相同成员(同类型、形参)可以覆盖基类成员。查找的顺序由派生类到基类。而对于指针引用来说,根据其声明的类型决定查找的开始范围!
//如果派生类需要使用基类中的重载函数,建议使用Using fun声明!避免在派生类中定义了同名函数,而导致覆盖!(作用域内,除了虚函数,应避免重定义基类中存在的成员对象)
//基类和派生类如需要拷贝移动赋值,则需要各自定义!(基类必须定义虚析构函数!)
//容器与继承,使用智能指针,避免派生类成员被丢弃!
vector<shared_ptr<Quote>> basket;
basket.push_back(make_shared<Quote>("c++", 150));//参数不同体现了,每个类各自负责自己的初始化!(利用构造函数初始化!)
basket.push_back(make_shared<Bulk_DiscQuote>("html", 150, 1, 0.2));
cout << basket.back()->net_price(4) << endl;
system("pause");
return 0;
}
//面向对象程序设计基于3个基本概念:数据抽象、继承和动态绑定!
//可以将基类的引用和指针绑定在派生类对象上,这是c++面向对象编程的关键所在!而派生类对象实质是不能向基类转换,当发生时,派生类非继承成员将被切掉!
//基类和派生类的虚函数默认实参最好一致!
chapter-15
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- Part 1 1. ambitiousambitious 造句:I have developed a ambiti...
- 没有什么比爱自己更重要的了。 身边的人、事大多存在变数,你根本无法知晓此刻的拥有下一秒是否还存在。最稳定的安全感,...