c/c++ 继承与多态 容器与继承3

c/c++ 继承与多态 容器与继承2 巩固了容器里放智能指针的用法,但是有个问题,对于使用Basket类的用户来说,必须添加的是智能指针,如果能直接添加一个普通的类的对象的话,用起来就方便的多了,所以改进一下Basket类的add_item接口。

新的接口:一个是拷贝给定的对象,另一个是移动对象。

void add_item(const Quote& sale);//左值拷贝
void add_item(Quote&& sale);//右值移动

关键点:

1,由于类Quote没有自定义的拷贝控制成员(拷贝构造函数,赋值语句等),所以,编译器才能自动生成移动构造函数,后面要用到编译器生成移动构造函数。

2,由于key是智能指针,所以在方法add_item里必须要有new,问题来了,new谁呢,只能new父类Quote,但是new了Quote后,子类部分就被切除掉了。

3,为了解决在2处的问题,在Quote和它的子类里添加辅助的虚函数,来得到正确的指针。得到了正确的普通指针就可以用普通指针做出智能指针了。

Quote4.h

#ifndef __QUOTE4_H__
#define __QUOTE4_H__

#include <iostream>

class Quote{
 public:
  Quote() = default;
  Quote(const std::string& book, double pri)
    :bookNo(book), price(pri){}
  std::string isbn() const{return bookNo;}

  //调用此方法的对象是左值的时候
  virtual Quote* clone() const & {
    //调用合成的拷贝构造函数
    return new Quote(*this);
  }

  ///调用此方法的对象是右值的时候
  virtual Quote* clone() && {
    //调用合成的移动构造函数
    return new Quote(std::move(*this));
  }

  virtual double net_price(std::size_t n)const{
    return n * price;
  }
  virtual void debug()const{
    std::cout << bookNo << " " << price << std::endl;
  }
  virtual ~Quote() = default;
 private:
  std::string bookNo;
 protected:
  double price = 0.0;
};

class Disc_quote : public Quote{
 public:
  Disc_quote() = default;
  Disc_quote(const std::string& book, double price,
         std::size_t qyn, double disc):Quote(book, price),
    quantity(qyn), discount(disc){}

  double net_price(std::size_t) const override = 0;
 protected:
  std::size_t quantity = 0;//折扣适用的数量
  double discount = 0.0;   //折扣率
};

class Bulk_quote : public Disc_quote{
 public:

  Bulk_quote() = default;

  Bulk_quote(const std::string& book, double price,
  std::size_t qyn, double disc)
  :Disc_quote(book, price, qyn, disc){}

  //调用此方法的对象是左值的时候
  Bulk_quote* clone() const & {
    //调用合成的拷贝构造函数
    return new Bulk_quote(*this);
  }

  ///调用此方法的对象是右值的时候
  Bulk_quote* clone() && {
    //调用合成的移动构造函数
    return new Bulk_quote(std::move(*this));
  }

  double net_price(std::size_t) const override;
};

class Min_quote : public Disc_quote{
 public:

  Min_quote() = default;
  Min_quote(const std::string& book, double price,
       std::size_t qyn, double disc)
   :Disc_quote(book, price, qyn, disc){}

  double net_price(std::size_t) const override;
};

#endif

Quote4.cpp

#include "Quote4.h"

double Bulk_quote::net_price(std::size_t cnt) const{
  if(cnt >= quantity){
    return cnt * (1 - discount) * price;
  }
  else{
    return cnt * price;
  }
}

double Min_quote::net_price(std::size_t cnt) const{
  if(cnt < quantity){
    return cnt * (1 - discount) * price;
  }
  else{
    return cnt * price;
  }
}

Basket2.h

#ifndef __BASKET2_H__
#define __BASKET2_H__
#include "Quote4.h"
#include <set>
#include <memory>

class Basket{
 public:
  /*
  void add_item(const std::shared_ptr<Quote>& sale){
    items.insert(sale);
  }
  */

  void add_item(const Quote& sale){
    items.insert(std::shared_ptr<Quote>(sale.clone()));
  }
  void add_item(Quote&& sale){
    items.insert(std::shared_ptr<Quote>(std::move(sale).clone()));
  }

  double total_receipt(std::ostream&) const;
 private:
  static bool compare(const std::shared_ptr<Quote>& lhs,
              const std::shared_ptr<Quote>& rhs){
    return lhs->isbn() < rhs->isbn();
  }
  std::multiset<std::shared_ptr<Quote>, decltype(compare)*>
    items{compare};
};

#endif

Basket2.cpp

#include "Basket.h"

double print_total(std::ostream& os,
           const Quote& item, size_t n);
double Basket::total_receipt(std::ostream& os) const{
  double sum = 0.0;
  for(auto iter = items.cbegin();
      iter != items.cend();
      iter = items.upper_bound(*iter)){
    sum += print_total(os, **iter, items.count(*iter));
  }
  os << "Total Sale: " << sum << std::endl;
  return sum;
}

main.cpp

#include "Quote4.h"
#include "Basket2.h"
#include <vector>
#include <iostream>

double print_total(std::ostream& os,
           const Quote& item, size_t n){
  double ret = item.net_price(n);
  os << "ISBN: " << item.isbn()
     << " # sold: " << n << " total due: " << ret << std::endl;
  return ret;

}

int main(){
  Basket bsk;
  Quote q1("01", 100);
  Bulk_quote bq1("01", 100, 2, 0.1);
  bsk.add_item(Quote("01", 100));

  bsk.add_item(Bulk_quote("01", 100, 2, 0.1));

  bsk.total_receipt(std::cout);
}

c/c++ 学习互助QQ群:877684253

本人微信:xiaoshitou5854

原文地址:https://www.cnblogs.com/xiaoshiwang/p/10220481.html

时间: 2024-07-30 13:47:53

c/c++ 继承与多态 容器与继承3的相关文章

c/c++ 继承与多态 容器与继承1

问题:类B公有继承类A,类A有虚函数fun,类B覆盖了虚函数fun,有一个std::vector<A>,添加A的对象a,和B的对象b,到这个容器里,然后从vector里取出来,使用对象a.fun(),和对象b.fun(),会发生什么? 发现对象b.fun()的调用,实际调用的是父类A的fun()方法.也就是子类部分被切掉了. 如何解决呢,用std::vector<A*>或者std::vector<std::shared_ptr<A>> ,但推荐用智能指针.

lua面向对象实现(实例化对象、继承、多态、多继承、单例模式)

lua面向对象实现: 一个类就像是一个创建对象的模具.有些面向对象语言提供了类的概念,在这些语言中每个对象都是某个特定类的实例.lua则没有类的概念,每个对象只能自定义行为和形态.不过,要在lua中模拟类也并不困难. lua中,面向对象是用元表这个机制来实现. 首先,一般来说一个表和它的元表是不同的个体(不属于同一个表),在创建新的表时,不会自动创建元表. setmetatable函数:设置元表 setmetatable( 表1 , 表2 )  将表2挂接为表1的元表,并且返回经过挂接后的表1

【继承与多态】C++:继承中的赋值兼容规则,子类的成员函数,虚函数(重写),多态

实现基类(父类)以及派生类(子类),验证继承与转换--赋值兼容规则: 子类对象可以赋值给父类对象(切割/切片) 父类对象不能赋值给子类对象 父类的指针/引用可以指向子类对象 子类的指针/引用不能指向父类对象(可以通过强制类型转换完成) #include<iostream> using namespace std; class People    //父类或者基类 { public:     void Display()     {         cout << "_na

12:面向对象三大特性(封装、继承、多态)之继承

本小节知识点: 继承基本概念 OC中的继承关系 OC中如何实现继承 1.继承基本概念 现实生活中的继承 交通工具类是一个基类(也称做父类),通常情况下所有交通工具所共同具备的特性,如速度与额定 载人的数量 按照生活常规,我们来继续给交通工具来细分类的时候,我们会分别想到有汽车类和飞机类等 等,汽车类和飞机类同样具备速度和额定载人数量这样的特性,而这些特性是所有交通工具所共有的,那么就可以让汽车或飞机类继承交通工具类,这样当建立汽车类和飞机类的时候我们无需再定义交通工具类(基类)中已经有的成员和方

第10章 接口、继承与多态 类的继承

1Test2类继承Test类,在子类中可以连同初始化父类构造方法来完成子类初始化操作,既可以在子类的构造方法中使用super()语句调用父类的构造方法,也可以在子类中使用super关键字调用父类的成员方法等,但是子类没有权限调用父类中被修饰为private的方法,只可以调用父类中修饰为public或protected的成员方法等. 2继承并不只是扩展父类的功能,还可以重写父类的成员方法.重写(还可以称为覆盖)就是在子类中将父类的成员方法的名称保留,重写成员方法的实现内容,更改成员方法的存储权限,

第10章 接口、继承与多态 类的继承3

尝试创建一个父类,在父类中创建两个方法,在子类中创建覆盖第二个方法,为子类创建一个对象,将向上转型到基类并调用这个方法 class Testmain{ public static void method1(Testmain q){ System.out.println(1); } public static void method2(){ System.out.println(2); } } public class Test extends Testmain { public static v

第10章 接口、继承与多态 类的继承2

在Java中一切都以对象的形式进行处理. 1)实例化子类对象时首先要实例化父类对象,然后再实例化子类对象,所以在子类构造方法访问父类的构造方法之前,父类已经完成实例化操作: 2)在实例化子类对象时,父类无参构造方法将被自动调用,但有参构造方法并不能被自动调用,只能依赖于super关键字显式地调用父类的构造方法. package ten; class Parent { Parent(){ System.out.println("调用父类的parent()构造方法"); } } class

继承与多态

继承与多态 一.继承 子类继承父类,通过在类后面加冒号来继承某个类A:B. 继承的作用:一旦形成继承关系后,子类的对象就能够使用父类中的公共属性和方法函数 ㈠继承关系中的方法重写.虚(抽象)方法.虚(抽象)属性 ⒈重写: 当子类中重写了跟父类同名同参数的方法之后,子类创建对象后,调用的是该子类里面的同名方法. ⒉父类变量与子类变量之间转换的规则: ⑴可以定义一个父类变量,用来存储子类对象(若有函数重写,存储了子类对象的父类变量调用方法时仍访问父类的同名方法,无法调用原先子类重写的方法以及特有的方

接口、继承、多态

接口.继承.多态 继承和多态是面向对象开发语言中非常重要的饿一个环节,如果在程序中使用继承和多态得当,整个程序的架构将变得非常有弹性,通知书可以减少代码的冗余性. 继承机制的使用可以复用一些定义好的类,减少重复代码的编写.多态机制的使用可以动态调整对象的调用,降低对象之间的依存关系. 1.继承机制中子类的结构化过程 子类的所构造函数,默认都会访问谷类中控参数的构造函数:因为,子类每一个构造行数内的第一行都由依据隐式的super(); 子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的,