Please indicate the source: http://blog.csdn.net/gaoxiangnumber1
Welcome to my github: https://github.com/gaoxiangnumber1
Inheritance
class Quote
{
public:
string isbn() const;
virtual double net_price(size_t n) const;
};
class Bulk_quote: public Quote // Bulk_quote inherits from Quote
{
public:
double net_price(size_t) const override;
};
Dynamic Binding
// calculate and print the price for the given number of copies, applying any discounts
double print_total(ostream &os, const Quote &item, size_t n)
{
// depending on the type of the object bound to the item parameter
// calls either Quote::net_price or Bulk_quote::net_price
double ret = item.net_price(n);
os << "ISBN: " << item.isbn() // calls Quote::isbn
<< " # sold: " << n << " total due: " << ret << endl;
return ret;
}
// basic has type Quote; bulk has type Bulk_quote
print_total(cout, basic, 20); // calls Quote version of net_price
print_total(cout, bulk, 20); // calls Bulk_quote version of net_price
class Quote
{
public:
Quote() = default; // = default see §7.1.4
Quote(const std::string &book, double sales_price):
bookNo(book), price(sales_price) {}
std::string isbn() const
{
return bookNo;
}
// returns the total sales price for the specified number of items
// derived classes will override and apply different discount algorithms
virtual double net_price(std::size_t n) const
{
return n * price;
}
virtual ~Quote() = default; // dynamic binding for the destructor
private:
std::string bookNo; // ISBN number of this item
protected:
double price = 0.0; // normal, undiscounted price
};
Member Functions and Inheritance
virtual
appears only on the declaration inside the class and may not be used on a function definition outside the class body. A function that is declared as virtual in the base class is implicitly virtual in the derived classes.Access Control and Inheritance
protected
access specifier.What is a virtual member?
How does the protected access specifier differ from private?
Define your own versions of the Quote class and the print_total function.
#include
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; // dynamic binding for the destructor
private:
string bookNo; // ISBN number of this item
protected:
double price = 0.0; // normal, un-discounted price
};
class Bulk_quote: public Quote // Bulk_quote inherits from Quote
{
public:
double net_price(size_t) const override;
};
double print_total(ostream &os, const Quote &item, size_t n)
{
double ret = item.net_price(n);
os << "ISBN: " << item.isbn() << " # sold: "
<< n << " total due: " << ret << endl;
return ret;
}
class Bulk_quote: public Quote // Bulk_quote inherits from Quote
{
Bulk_quote() = default;
Bulk_quote(const string&, double, size_t, double);
double net_price(size_t) const override;
private:
size_t min_qty = 0; // minimum purchase for the discount to apply
double discount = 0.0; // fractional discount to apply
};
Virtual Functions in the Derived Class
virtual
on the functions it overrides, but not required. C++11 lets a derived class explicitly note that it intends a member function to override a virtual that it inherits by specifying override
after the parameter list, or after the const or reference qualifier if the member is a const(7.1.2) or reference (13.6.3) function.Derived-Class Objects and the Derived-to-Base Conversion
bookNo
and price
that inherits from Quote, min_qty
and discount
that defined by Bulk_quote. 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
Derived-Class Constructors
Bulk_quote(const string &book, double p, size_t qty, double disc):
Quote(book, p), min_qty(qty), discount(disc) {}
Using Members of the Base Class from the Derived Class
// if the specified number of items are purchased, use the discounted price
double Bulk_quote::net_price(size_t cnt) const
{
if(cnt >= min_qty)
{
return cnt * (1 - discount) * price;
}
else
{
return cnt * price;
}
}
Inheritance and static Members
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 Classes
class Bulk_quote : public Quote; // error: derivation list can't appear here
class Bulk_quote; // ok: right way to declare a derived class
Classes Used as a Base 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
Which of the following declarations, if any, are incorrect? Explain why.
class Base { ... };
(a) class Derived : public Derived { ... };
(b) class Derived : private Base { ... };
(c) class Derived : public Base;
Define your own version of the Bulk_quote class.
Test your print_total function from the exercises in 15.2.1(p. 595) by passing both Quote and Bulk_quote objects to that function.
#include
#include
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; // ISBN number of this item
protected:
double price = 0.0; // normal, undiscounted price
};
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) {}
double net_price(size_t) const override;
private:
size_t min_qty = 0; // minimum purchase for the discount to apply
double discount = 0.0; // fractional discount to apply
};
// if the specified number of items are purchased, use the discounted price
double Bulk_quote::net_price(size_t cnt) const
{
if(cnt >= min_qty)
{
return cnt * (1 - discount) * price;
}
else
{
return cnt * price;
}
}
double print_total(ostream &os, const Quote &item, size_t n)
{
double ret = item.net_price(n);
os << "ISBN: " << item.isbn() << " # sold: "
<< n << " total due: " << ret << endl;
return ret;
}
int main()
{
Quote base("hello", 100);
Bulk_quote derive("world", 100, 5, 0.1);
print_total(cout, base, 10);
print_total(cout, derive, 10);
return 0;
}
/*
Output:
ISBN: hello # sold: 10 total due: 1000
ISBN: world # sold: 10 total due: 900
*/
Define a class that implements a limited discount strategy, which applies a discount to books purchased up to a given limit. If the number of copies exceeds that limit, the normal price applies to those purchased beyond the limit.
Static Type and Dynamic Type
There Is No Implicit Conversion from Base to Derived …
Quote base;
Bulk_quote* bulkP = &base; // error: can't convert base to derived
Bulk_quote& bulkRef = base; // error: can't convert base to derived
Bulk_quote bulk;
Quote *itemP = &bulk; // ok: dynamic type is Bulk_quote
Bulk_quote *bulkP = itemP; // error: can't convert base to derived
…and No Conversion between Objects
Bulk_quote bulk; // object of derived type
Quote item(bulk); // uses the Quote::Quote(const Quote&) constructor
item = bulk; // calls Quote::operator=(const Quote&)
Define static type and dynamic type.
When is it possible for an expressions static type to differ from its dynamic type? Give three examples in which the static and dynamic type differ.
Recalling the discussion from 8.1(p. 311), explain how the program on page 317 that passed an ifstream to the Sales_data read function works.
Key Concept: Conversions among Types Related by Inheritance
Calls to Virtual Functions May Be Resolved at Run Time
Quote base("0-201-82470-1", 50);
print_total(cout, base, 10); // calls Quote::net_price
Bulk_quote derived("0-201-82470-1", 50, 5, .19);
print_total(cout, derived, 10); // calls Bulk_quote::net_price
base = derived; // copies the Quote part of derived into base
base.net_price(20); // calls Quote::net_price
Key Concept: Polymorphism in C++
Virtual Functions in a Derived Class
virtual
because once a function is declared as virtual, it remains virtual in all the derived classes.The final and override Specifiers
struct B
{
virtual void f1(int) const;
virtual void f2();
void f3();
};
struct D1 : B
{
void f1(int) const override; // ok: f1 matches f1 in the base
void f2(int) override; // error: B has no f2(int) function
void f3() override; // error: f3 not virtual
void f4() override; // error: B doesn't have a function named f4
};
struct D2 : B
{
// inherits f2() and f3() from B and overrides f1(int)
void f1(int) const final; // subsequent classes can't override f1(int)
};
struct D3 : D2
{
void f2(); // ok: overrides f2 inherited from the indirect base, B
void f1(int) const; // error: D2 declared f2 as final
};
Virtual Functions and Default Arguments
Circumventing the Virtual Mechanism
// calls the version from the base class regardless of the dynamic type of baseP
double undiscounted = baseP->Quote::net_price(42);
Add a virtual debug function to your Quote class hierarchy that displays the data members of the respective classes.
#include
#include
using namespace std;
class Quote
{
public:
Quote(const string &book, double sales_price):
bookNo(book), price(sales_price) {}
virtual ~Quote() = default;
virtual void Debug() const
{
cout << "bookNo = " << bookNo << ", price = " << price << '\n';
}
protected:
string bookNo; // ISBN number of this item
double price = 0.0; // normal, undiscounted price
};
class Bulk_quote: public Quote
{
public:
Bulk_quote(const string &book, double p, size_t qty, double disc):
Quote(book, p), min_qty(qty), discount(disc) {}
void Debug() const override
{
cout << "bookNo = " << bookNo << ", price = " << price
<< ", min_qty = " << min_qty << ", discount = " << discount << '\n';
}
private:
size_t min_qty = 0; // minimum purchase for the discount to apply
double discount = 0.0; // fractional discount to apply
};
int main()
{
Quote base("hello", 100);
Bulk_quote derive("world", 100, 5, 0.1);
base.Debug();
derive.Debug();
return 0;
}
/*
Output:
bookNo = hello, price = 100
bookNo = world, price = 100, min_qty = 5, discount = 0.1
*/
Is it ever useful to declare a member function as both override and final? Why or why not?
Given the following classes, explain each print function:
class base
{
public:
string name()
{
return base_name;
}
virtual void print(ostream &os)
{
os << base_name;
}
private:
string base_name;
};
class derived : public base
{
public:
void print(ostream &os)
{
print(os);
os << " " << i;
}
private:
int i;
};
If there is a problem in this code, how would you fix it?
print(os)
in derived will call itself indefinitely.base::print(os);
Given the classes from the previous exercise and the following objects, determine which function is called at run time:
base bobj;
base *bp1 = &bobj;
base &br1 = bobj;
derived dobj;
base *bp2 = &dobj;
base &br2 = dobj;
(a) bobj.print();
(b) dobj.print();
(c) bp1->name();
(d) bp2->name();
(e) br1.print();
(f) br2.print();
#include
#include
using namespace std;
class base
{
public:
void name()
{
cout << basename << '\n';
}
virtual void print()
{
cout << "base\n";
}
private:
string basename = "default";
};
class derived : public base
{
public:
void print()
{
cout << "derived\n";
}
private:
int i = 7188;
};
int main()
{
base bobj;
base *bp1 = &bobj;
base &br1 = bobj;
derived dobj;
base *bp2 = &dobj;
base &br2 = dobj;
bobj.print();
dobj.print();
bp1->name();
bp2->name();
br1.print();
br2.print();
return 0;
}
/*
Output:
base
derived
default
default
base
derived
*/
Pure Virtual Functions
= 0
in place of a function body(i.e., just before the semicolon that ends the declaration). = 0
may appear only on the declaration of a virtual function in the class body. // class to hold the discount rate and quantity
// derived classes will implement pricing strategies using these data
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) const = 0;
protected:
size_t quantity = 0; // purchase size for the discount to apply
double discount = 0.0; // fractional discount to apply
};
Classes with Pure Virtuals Are Abstract Base Classes
// Disc_quote declares pure virtual functions, which Bulk_quote will override
Disc_quote discounted; // error: can't define a Disc_quote object
Bulk_quote bulk; // ok: Bulk_quote has no pure virtual functions
A Derived Class Constructor Initializes Its Direct Base Class Only
// the discount kicks in when a specified number of copies of the same book are sold
// the discount is expressed as a fraction to use to reduce the normal price
class Bulk_quote: public Disc_quote
{
public:
Bulk_quote() = default;
Bulk_quote(const string& book, double price, size_t qty, double disc):
Disc_quote(book, price, qty, disc) {}
// overrides the base version to implement the bulk purchase discount policy
double net_price(size_t) const override;
};
Key Concept: Refactoring
Define your own versions of Disc_quote and Bulk_quote.
// class to hold the discount rate and quantity
// derived classes will implement pricing strategies using these data
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) const = 0;
protected:
size_t quantity = 0; // purchase size for the discount to apply
double discount = 0.0; // fractional discount to apply
};
// the discount kicks in when a specified number of copies of the same book are sold
// the discount is expressed as a fraction to use to reduce the normal price
class Bulk_quote: public Disc_quote
{
public:
Bulk_quote() = default;
Bulk_quote(const string& book, double price, size_t qty, double disc):
Disc_quote(book, price, qty, disc) {}
// overrides the base version to implement the bulk purchase discount policy
double net_price(size_t) const override
{
return 0.0;
}
};
Rewrite the class representing a limited discount strategy, which you wrote for the exercises in 15.2.2(p. 601), to inherit from Disc_quote.
// if the specified number of items are purchased, use the discounted price
double Bulk_quote::net_price(size_t cnt) const
{
if(cnt >= quantity)
{
return cnt * (1 - discount) * price;
}
else
{
return cnt * price;
}
}
Try to define an object of type Disc_quote and see what errors you get from the compiler.
protected Members
protected
for members that it is willing to share with its derived classes but wants to protect from general access. class Base
{
protected:
int prot_mem; // protected member
};
class Sneaky : public Base
{
friend void clobber(Sneaky&); // can access Sneaky::prot_mem
friend void clobber(Base&); // can't access Base::prot_mem
int j; // j is private by default
};
// ok: clobber can access the private and protected members in Sneaky objects
void clobber(Sneaky &s)
{
s.j = s.prot_mem = 0;
}
// error: clobber can't access the protected members in Base
void clobber(Base &b)
{
b.prot_mem = 0;
}
public, private, and protected Inheritance
class Base
{
public:
void pub_mem(); // public member
protected:
int prot_mem; // protected member
private:
char priv_mem; // private member
};
struct Pub_Derv : public Base
{
// ok: derived classes can access protected members
int f()
{
return prot_mem;
}
// error: private members are inaccessible to derived classes
char g()
{
return priv_mem;
}
};
struct Priv_Derv : private Base
{
// private derivation doesn't affect access in the derived class
int f1() const
{
return prot_mem;
}
};
Pub_Derv d1; // members inherited from Base are public
Priv_Derv d2; // members inherited from Base are private
d1.pub_mem(); // ok: pub_mem is public in the derived class
d2.pub_mem(); // error: pub_mem is private in the derived class
struct Derived_from_Public : public Pub_Derv
{
// ok: Base::prot_mem remains protected in Pub_Derv
int use_base()
{
return prot_mem;
}
};
struct Derived_from_Private : public Priv_Derv
{
// error: all the members that Priv_Derv inherited from Base are private.
int use_base()
{
return prot_mem;
}
};
Prot_Derv
class use protected inheritance, the public members of Base would be protected members in that class. Users of Prot_Derv would have no access to pub_mem, but the members and friends of Prot_Derv could access that inherited member.Accessibility of Derived-to-Base Conversion
Key Concept: Class Design and protected Members
Friendship and Inheritance
class Base
{
// added friend declaration; other members as before
friend class Pal; // Pal has no access to classes derived from Base
};
class Pal
{
public:
int f(Base b)
{
return b.prot_mem; // ok: Pal is a friend of Base
}
int f2(Sneaky s)
{
return s.j; // error: Pal not friend of Sneaky
}
// access to a base class is controlled by the base class, even inside a derived object
int f3(Sneaky s)
{
return s.prot_mem; // ok: Pal is a friend
}
};
// D2 has no access to protected or private members in Base
class D2 : public Pal
{
public:
int mem(Base b)
{
return b.prot_mem; // error: friendship doesn't inherit
}
};
Exempting Individual Members
class Base
{
public:
size_t size() const
{
return n;
}
protected:
size_t n;
};
class Derived : private Base // note: private inheritance
{
public:
// maintain access levels for members related to the size of the object
using Base::size;
protected:
using Base::n;
};
Default Inheritance Protection Levels
class
has private inheritance; with struct
has public inheritance:class Base { /* ... */ };
struct D1: Base { /* ... */ }; // public inheritance by default
class D2: Base { /* ... */ }; // private inheritance by default
struct
and class
is the default access specifier for members and the default derivation access specifier.Given the classes from page 612 and page 613, and assuming each object has the type specified in the comments, determine which of these assignments are legal. Explain why those that are illegal aren’t allowed:
Base *p = &d1; // d1 has type Pub_Derv
p = &d2; // d2 has type Priv_Derv
p = &d3; // d3 has type Prot_Derv
p = &dd1; // dd1 has type Derived_from_Public
p = &dd2; // dd2 has type Derived_from_Private
p = &dd3; // dd3 has type Derived_from_Protected
#include
using namespace std;
class Base
{
public:
int pub_mem;
protected:
int prot_mem;
private:
char priv_mem;
};
struct Pub_Derv: public Base {};
struct Priv_Derv: private Base {};
struct Prot_Derv: protected Base {};
struct Derived_from_Public: public Pub_Derv {};
struct Derived_from_Private: public Priv_Derv {};
struct Derived_from_Protected: public Prot_Derv {};
int main()
{
Pub_Derv d1;
Priv_Derv d2;
Prot_Derv d3;
Derived_from_Public dd1;
Derived_from_Private dd2;
Derived_from_Protected dd3;
Base *p = &d1; // d1 has type Pub_Derv
// p = &d2; // d2 has type Priv_Derv
// p = &d3; // d3 has type Prot_Derv
p = &dd1; // dd1 has type Derived_from_Public
// p = &dd2; // dd2 has type Derived_from_Private
// p = &dd3; // dd3 has type Derived_from_Protected
return 0;
}
Assume that each of the classes from page 612 and page 613 has a member function of the form:
void memfcn(Base &b) { b = *this; }
For each class, determine whether this function would be legal.
#include
using namespace std;
class Base
{
public:
int pub_mem;
protected:
int prot_mem;
private:
char priv_mem;
};
struct Pub_Derv: public Base
{
void memfcn(Base &b)
{
b = *this;
}
};
struct Prot_Derv: protected Base
{
void memfcn(Base &b)
{
b = *this;
}
};
struct Priv_Derv: private Base
{
void memfcn(Base &b)
{
b = *this;
}
};
struct Derived_from_Public: public Pub_Derv
{
void memfcn(Base &b)
{
b = *this;
}
};
struct Derived_from_Protected: public Prot_Derv
{
void memfcn(Base &b)
{
b = *this;
}
};
struct Derived_from_Private: public Priv_Derv
{
/*void memfcn(Base &b)
{
b = *this;
}*/
};
int main()
{
Pub_Derv d1;
Priv_Derv d2;
Prot_Derv d3;
Derived_from_Public dd1;
Derived_from_Private dd2;
Derived_from_Protected dd3;
return 0;
}
Write code to test your answers to the previous two exercises.
Choose one of the following general abstractions containing a family of types(or choose one of your own). Organize the types into an inheritance hierarchy:
(a) Graphical file formats(such as gif, tiff, jpeg, bmp)
(b) Geometric primitives(such as box, circle, sphere, cone)
(c) C++ language types(such as class, function, member function)
For the class you chose in the previous exercise, identify some of the likely virtual functions as well as public and protected members.
Name Lookup Happens at Compile Time
class Disc_quote : public Quote
{
public:
pairdouble> discount_policy() const
{
return {quantity, discount};
}
// other members as before
};
class Bulk_quote: public Disc_quote {...};
Bulk_quote bulk;
Bulk_quote *bulkP = &bulk; // static and dynamic types are the same
Quote *itemP = &bulk; // static and dynamic types differ
bulkP->discount_policy(); // ok: bulkP has type Bulk_quote*
itemP->discount_policy(); // error: itemP has type Quote*
Name Collisions and Inheritance
struct Base
{
Base(): mem(0) {}
protected:
int mem;
};
struct Derived : Base
{
Derived(int i): mem(i) {} // initializes Derived::mem to i
// Base::mem is default initialized
int get_mem()
{
return mem; // returns Derived::mem
}
protected:
int mem; // hides mem in the base
};
Using the Scope Operator to Use Hidden Members
struct Derived : Base
{
int get_base_mem()
{
return Base::mem;
}
// ...
};
Key Concept: Name Lookup and Inheritance
p->mem(); or
obj.mem();
As Usual, Name Lookup Happens before Type Checking
struct Base
{
int memfcn();
};
struct Derived : Base
{
int memfcn(int); // hides memfcn in the base
};
Derived d;
Base b;
b.memfcn(); // calls Base::memfcn
d.memfcn(10); // calls Derived::memfcn
d.memfcn(); // error: memfcn with no arguments is hidden
d.Base::memfcn(); // ok: calls Base::memfcn
Virtual Functions and Scope
class Base
{
public:
virtual int fcn();
};
class D1 : public Base
{
public:
// hides fcn in the base; this fcn is not virtual
// D1 inherits the definition of Base::fcn()
int fcn(int); // parameter list differs from fcn in Base
virtual void f2(); // new virtual function that does not exist in Base
};
class D2 : public D1
{
public:
int fcn(int); // nonvirtual function hides D1::fcn(int)
int fcn(); // overrides virtual fcn from Base
void f2(); // overrides virtual f2 from D1
};
Calling a Hidden Virtual through the Base Class
Base bobj;
D1 d1obj;
D2 d2obj;
Base *bp1 = &bobj, *bp2 = &d1obj, *bp3 = &d2obj;
bp1->fcn(); // virtual call, will call Base::fcn at run time
bp2->fcn(); // virtual call, will call Base::fcn at run time
bp3->fcn(); // virtual call, will call D2::fcn at run time
D1 *d1p = &d1obj;
D2 *d2p = &d2obj;
bp2->f2(); // error: Base has no member named f2
d1p->f2(); // virtual call, will call D1::f2() at run time
d2p->f2(); // virtual call, will call D2::f2() at run time
Base *p1 = &d2obj;
D1 *p2 = &d2obj;
D2 *p3 = &d2obj;
p1->fcn(42); // error: Base has no version of fcn that takes an int
p2->fcn(42); // statically bound, calls D1::fcn(int)
p3->fcn(42); // statically bound, calls D2::fcn(int)
Overriding Overloaded Functions
Assuming class D1 on page 620 had intended to override its inherited fcn function, how would you fix that class? Assuming you fixed the class so that fcn matched the definition in Base, how would the calls in that section be resolved?
int
.#include
using namespace std;
class Base
{
public:
virtual int fcn()
{
cout << "Base::fcn()\n";
return 0;
}
};
class D1 : public Base
{
public:
int fcn() override
{
cout << "D1::fcn()\n";
return 0;
}
virtual void f2()
{
cout << "D1::f2()\n";
}
};
class D2 : public D1
{
public:
int fcn(int)
{
cout << "D2::fcn(int)\n";
}
int fcn() override
{
cout << "D2::fcn()\n";
return 0;
}
void f2() override
{
cout << "D2::f2()\n";
}
};
int main()
{
Base bobj;
D1 d1obj;
D2 d2obj;
Base *bp1 = &bobj, *bp2 = &d1obj, *bp3 = &d2obj;
bp1->fcn(); // virtual call, will call Base::fcn at run time
bp2->fcn(); // virtual call, will call D1::fcn at run time
bp3->fcn(); // virtual call, will call D2::fcn at run time
D1 *d1p = &d1obj;
D2 *d2p = &d2obj;
//bp2->f2(); // error: ‘class Base’ has no member named ‘f2’
d1p->f2(); // virtual call, will call D1::f2() at run time
d2p->f2(); // virtual call, will call D2::f2() at run time
return 0;
}
/*
Output:
Base::fcn()
D1::fcn()
D2::fcn()
D1::f2()
D2::f2()
*/
class Quote
{
public:
// virtual destructor needed if a base pointer pointing to a derived object is deleted
virtual ~Quote() = default; // dynamic binding for the destructor
};
Quote *itemP = new Quote; // same static and dynamic type
delete itemP; // destructor for Quote called
itemP = new Bulk_quote; // static and dynamic types differ
delete itemP; // destructor for Bulk_quote called
Virtual Destructors Turn Off Synthesized Move
What kinds of classes need a virtual destructor? What operations must a virtual destructor perform?
Base Classes and Deleted Copy Control in the Derived
class B
{
public:
B();
B(const B&) = delete;
// other members, not including a move constructor
};
class D : public B
{
// no constructors
};
D d; // ok: D's synthesized default constructor uses B's default constructor
D d2(d); // error: D's synthesized copy constructor is deleted
D d3(move(d)); // error: implicitly uses D's deleted copy constructor
Move Operations and Inheritance
class Quote
{
public:
Quote() = default; // memberwise default initialize
Quote(const Quote&) = default; // memberwise copy
Quote(Quote&&) = default; // memberwise copy
Quote& operator=(const Quote&) = default; // copy assign
Quote& operator=(Quote&&) = default; // move assign
virtual ~Quote() = default;
// other members as before
};
Why did we define a default constructor for Disc_quote? What effect, if any, would removing that constructor have on the behavior of Bulk_quote?
Bulk_quote obj; // error: use of deleted function ‘Bulk_quote::Bulk_quote()’
Defining a Derived Copy or Move Constructor
class Base
{
/* ... */
};
class D: public Base
{
public:
// by default, the base class default constructor initializes the base part of an object
// to use the copy or move constructor, we must explicitly call that
// constructor in the constructor initializer list
D(const D& d): Base(d) // copy the base members
/* initializers for members of D */
{
/* ... */
}
D(D&& d): Base(std::move(d)) // move the base members
/* initializers for members of D */
{
/* ... */
}
};
Base(d)
passes a D object to a base-class constructor. Base(d)
ordinarily match the Base copy constructor and d is bound to the Base& parameter. The Base copy constructor will copy the base part of d into the object that is being created.// probably incorrect definition of the D copy constructor
// base-class part is default initialized, not copied
D(const D& d) // member initializers, but no base-class initializer
{
/* ... */
}
Derived-Class Assignment Operator
// Base::operator=(const Base&) is not invoked automatically
D &D::operator=(const D &rhs)
{
Base::operator=(rhs); // assigns the base part
// assign the members in the derived class, as usual,
// handling self-assignment and freeing existing resources as appropriate
return *this;
}
Derived-Class Destructor
class D: public Base
{
public:
// Base::~Base invoked automatically
~D()
{
/* do what it takes to clean up derived members */
}
};
Calls to Virtuals in Constructors and Destructors
Define the Quote and Bulk_quote copy-control members to do the same job as the synthesized versions. Give them and the other constructors print statements that identify which function is running. Write programs using these classes and predict what objects will be created and destroyed. Compare your predictions with the output and continue experimenting until your predictions are reliably correct.
class Bulk_quote: public Disc_quote
{
public:
using Disc_quote::Disc_quote; // inherit Disc_quote's constructors
double net_price(std::size_t) const;
};
Bulk_quote(const string& book, double price, size_t qty, double disc):
Disc_quote(book, price, qty, disc) {}
Characteristics of an Inherited Constructor
Redefine your Bulk_quote class to inherit its constructors.
vector
basket;
basket.push_back(Quote("0-201-82470-1", 50));
// ok, but copies only the Quote part of the object into basket
basket.push_back(Bulk_quote("0-201-54848-8", 50, 10, .25));
// calls version defined by Quote, prints 750, i.e., 15 * $50
cout << basket.back().net_price(15) << endl;
Put(Smart) Pointers, Not Objects, in Containers
vector<shared_ptr
> basket;
basket.push_back(make_shared("0-201-82470-1", 50));
basket.push_back(make_shared("0-201-54848-8", 50, 10, .25));
// calls the version defined by Quote; prints 562.5, i.e., 15 * $50 less the discount
cout << basket.back()->net_price(15) << endl;
make_shared
returns a shared_ptr object, which is converted to shared_ptr when we call push_back. So, all elements of basket have the same type.Define a vector to hold Quote objects but put Bulk_quote objects into that vector. Compute the total net_price of all the elements in the vector.
Repeat your program, but this time store shared_ptrs to objects of type Quote. Explain any discrepancy in the sum generated by the this version and the previous program. If there is no discrepancy, explain why there isn’t one.
Chapter Summary
Please indicate the source: http://blog.csdn.net/gaoxiangnumber1
Welcome to my github: https://github.com/gaoxiangnumber1