An Overview
class Quote
{
public:
Quote() = default; //price = 0.0,bookNo = ""
Quote(const std::string& book,const double sales_price)
:bookNo(book),price(sales_price){}
std::string isbn() const{return bookNo;}
virtual double net_price(const std::size_t n) const {return n*price;}
virtual ~Quote() = default; //dynamic binding for the destructor
protected:
double price = 0.0;
private:
std::string bookNo;
};
void print_total(std::ostream& os,const Quote &item,std::size_t n)
{
double ret = item.net_price(n);
os<<"ISBN: "<<item.isbn()//calls Quote::isbn
<<"# sold: "<<n<<" total due: "<<ret<<std::endl;
}
class Bluk_quote : public Quote
{
public:
Bluk_quote() = default;
Bluk_quote(const std::string& book,const double sales_price,const std::size_t& qty,const double& d)
:Quote(book,sales_price),min_qty(qty),discount(d){}
virtual double net_price(std::size_t n) const override
{
if(n>=min_qty)
return n*(1-discount)*price;
else
return n*price;
}
private:
std::size_t min_qty = 0; //minimum purchase for the discount to apply
double discount = 0.0; //fractional discount to display
};
What is a virtual member?
A virtual member in a base class expects its derived class define its own version. In particular base classes ordinarily should define a virtual destructor, even if it does no work.
How does the protected access specifier differ from private?
- private member: base class itself and friend can access
- protected members: base class itself, friend and derived classes can access
Quote item; // object of base type
Bulk_quote bulk; // object of derived type
Quote *p = &item; // p points to a Quote object
p = &bulk; // p points to the Quote part of bulk
Quote &r = bulk; // r bound to the Quote part of bulk
object of derived type or a reference to a derived type when a reference to the base
type is required. Similarly, we can use a pointer to a derived type where a pointer to
the base type is required
to how inheritance works
Bulk_quote(const std::string& book, double p,
std::size_t qty, double disc) :
Quote(book, p), min_qty(qty), discount(disc) { }
// as before
};
object of derived type or a reference to a derived type when a reference to the base
type is required. Similarly, we can use a pointer to a derived type where a pointer to
the base type is required
to how inheritance works
Using Members of the Base Class from the Derived Class
member defined for the entire hierarchy. Regardless of the number of classes derived
from a base class, there exists a single instance of each static member
class Base
{
public:
static void statmem();
};
class Derived : public Base
{
void f(const Derived&);
};
void Derived::f(const Derived &derived_obj)
{
Base::statmem(); // ok: Base defines statmem
Derived::statmem(); // ok: Derived inherits statmem
// ok: derived objects can be used to access static from base
derived_obj.statmem(); // accessed through a Derived object
statmem(); // accessed through this object
}
Declarations of Derived ClassesA derived class is declared like any other class (§7.3.3, p. 278). The declaration contains the class name but does not include its derivation list:
class Bulk_quote : public Quote; // error: derivation list can't appear here
class Bulk_quote; // ok: right way to declare a derived class
class Quote; // declared but not defined
// error: Quote must be defined
class Bulk_quote : public Quote { ... };
class Base { /* ... */ } ;
class D1: public Base { /* ... */ };
class D2: public D1 { /* ... */ };
Preventing Inheritance
class NoDerived final { /* */ }; // NoDerived can't be a base class
class Base { /* */ };
// Last is final; we cannot inherit from Last
class Last final : Base { /* */ }; // Last can't be a base class
class Bad : NoDerived { /* */ }; // error: NoDerived is final
class Bad2 : Last { /* */ }; // error: Last is final