Chapter 15 object oriented programming (1 ~ 27)

Keywords: C++

C++ Primer Chinese Version (5th Edition) practice solution collection

Write your own answers. If there are mistakes, please correct them in the comment area!

1

For some members, the base class wants its derived classes to customize their own versions (rather than directly inherit without change). At this time, the base class defines these members as virtual members.

2

For protected, the derived class has access, but other users cannot

For private, neither derived classes nor other users can access it

3

#pragma once
#include <iostream>
using std::ostream;
using std::endl;
#include <string>
using std::string;

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:
	double net_price(size_t) const override;
};

double printTotal(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;
}

4

a. Incorrect, a class cannot derive itself

b. Right

c. Incorrect. The derived list cannot be written in the declaration. These details should be placed in the body of the class.

5

#pragma once
#include <iostream>
using std::ostream;
using std::endl;
#include <string>
using std::string;

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 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;
	double discount = 0.0;
};

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

double printTotal(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;
}

6

See the previous question for the Quote.h code.

CppPrimerCh15.cpp:

#include <iostream>
#include "Quote.h"
using namespace std;

int main()
{
    Quote q("Harry Potter", 15.0);
    Bulk_quote bq("C++ Primer", 65.0, 3, 0.5);
    printTotal(cout, q, 5);
    printTotal(cout, bq, 5);
    return 0;
}

Operation results:

ISBN: Harry Potter # sold: 5 total due: 75
ISBN: C++ Primer # sold: 5 total due: 162.5

7

class Limited_bulk_quote : public Quote {
public:
	Limited_bulk_quote() = default;
	Limited_bulk_quote(const string& book, double p, size_t qty, double disc) :
		Quote(book, p), max_qty(qty), discount(disc) { }
	double net_price(size_t) const override;

private:
	size_t max_qty = 0;
	double discount = 0.0;
};

double Limited_bulk_quote::net_price(size_t cnt) const {
	if (cnt <= max_qty)
		return cnt * (1 - discount) * price;
	else
		return cnt * price;
}

8

A static type is always known at compile time. It is the type when a variable is declared or the type generated by an expression

Dynamic types are the types of objects in memory represented by variables or expressions. Dynamic types are not known until runtime

9

#include <iostream>
#include "Quote.h"
using namespace std;

int main()
{
    Bulk_quote derived;
    Limited_bulk_quote anotherDerived;
    Quote* baseP = &derived;
    Quote& baseR = derived;
    Quote& baseR1 = anotherDerived;
    return 0;
}

10

The first parameter of the read function accepts a reference to iostream, which is actually called with ifstream type. This is an implicit conversion from a derived class to a base class (only valid for pointer or reference types). Because the derived class includes members of the base class, the reference of iostream can point to this part of the base class in the derived class.

11

#pragma once
#include <iostream>
using std::ostream;
using std::cout;
using std::endl;
#include <string>
using std::string;

/*=============================================
					Quote
=============================================*/
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;

	virtual void debug() const {
		cout << "bookNo: " << bookNo
			<< "\nprice: " << price << endl;
	}

private:
	string bookNo;
protected:
	double price = 0.0;
};

double printTotal(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;
}

/*=============================================
				Bulk_quote
=============================================*/
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;

	virtual void debug() const override {
		cout << "min_qty: " << min_qty
			<< "\ndiscount: " << discount << endl;
	}

private:
	size_t min_qty = 0;
	double discount = 0.0;
};

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

CppPrimerCh15.cpp:

#include <iostream>
#include "Quote.h"
using namespace std;

int main() {
    Quote base("Harry Potter", 15.0);
    Bulk_quote derived("C++ Primer", 65.0, 3, 0.5);
    base.debug();
    putchar('\n');
    derived.debug();
    putchar('\n');
    derived.Quote::debug();
    return 0;
}

Operation results:

bookNo: Harry Potter
price: 15

min_qty: 3
discount: 0.5

bookNo: C++ Primer
price: 65

12

You can do this when necessary. The two keywords do not conflict:

  • Override keyword declares that the function is an override of a virtual function in the base class, which helps the compiler find errors. If the parameter list is inconsistent with the virtual function in the base class, the compiler will report an error to prevent the compiler from mistaking it as an overload
  • The final keyword declares that the function is not allowed to be overridden by derived classes

13

There is a problem. The print function is called in the body of the print function in the derived class. The original intention is to call the print in the base class. However, if the scope is not indicated explicitly, the call itself will cause infinite recursion. Another problem is that it is best to add override after the function header overridden by the derived class to prevent the parameter list from being written incorrectly.

#include <iostream>
#include "Quote.h"
using namespace std;

class Base {
public:
    string name() { 
        return basename;
    }
    virtual void print(ostream& os) {
        os << basename;
    }

private:
    string basename;
};

class Derived : public Base {
public:
    void print(ostream &os) override {
        Base::print(os);
        os << " " << i;
    }
private:
    int i;
};

int main() {
    Derived d;
    d.print(cout);
    return 0;
}

14

a. base::print()

b. derived::print()

c. base::name()

d. base::name()

e. base::print()

f. derived::print()

15

#pragma once
#include <iostream>
using std::ostream;
using std::cout;
using std::endl;
#include <string>
using std::string;

/*=============================================
					Quote
=============================================*/
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;

	virtual void debug() const {
		cout << "bookNo: " << bookNo
			<< "\nprice: " << price << endl;
	}

private:
	string bookNo;
protected:
	double price = 0.0;
};

double printTotal(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;
}

/*=============================================
				Disc_quote
=============================================*/
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;
	double discount = 0.0;
};

/*=============================================
				Bulk_quote
=============================================*/
class Bulk_quote : public Disc_quote {
public:
	Bulk_quote() = default;
	Bulk_quote(const string& book, double p, size_t qty, double disc) :
		Disc_quote(book, p, qty, disc) { }
	double net_price(size_t) const override;

	virtual void debug() const override {
		cout << "min_qty: " << min_qty
			<< "\ndiscount: " << discount << endl;
	}

private:
	size_t min_qty = 0;
	double discount = 0.0;
};

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

/*=============================================
			Limited_bulk_quote
=============================================*/

class Limited_bulk_quote : public Disc_quote {
public:
	Limited_bulk_quote() = default;
	Limited_bulk_quote(const string& book, double p, size_t qty, double disc) :
		Disc_quote(book, p, qty, disc) { }
	double net_price(size_t) const override;

private:
	size_t max_qty = 0;
	double discount = 0.0;
};

double Limited_bulk_quote::net_price(size_t cnt) const {
	if (cnt <= max_qty)
		return cnt * (1 - discount) * price;
	else
		return cnt * price;
}

16

See 15

17

Objects of abstract class type 'Disc_quote' are not allowed

Function double net_price(size_t) const is a pure virtual function

18

// Only when D inherits B publicly can user code use the conversion from D to B
Base *p = &d1;	// correct
p = &d2;		// error
p = &d3;		// error

// The same is true for derived classes of derived classes
// Only when DD inherits D publicly can user code use the conversion from DD to D, and then from D to B
p = &dd1;		// correct
p = &dd2;		// error
p = &dd3;		// error

19

class Base {
public:
    int pub_mem;
protected:
    int prot_mem;
private:
    int priv_mem;
};

class Pub_Derv : public Base {
    void memfcn(Base& b) { b = *this; }
};

class Prot_Derv : protected Base {
    void memfcn(Base& b) { b = *this; }
};

class Priv_Derv : private Base {
    void memfcn(Base& b) { b = *this; }
};

class Derived_from_Public : public Pub_Derv {
    void memfcn(Base& b) { b = *this; }
};

class Derived_from_Protected : public Prot_Derv {
    void memfcn(Base& b) { b = *this; }
};

class Derived_from_Private : public Priv_Derv {
    void memfcn(Base& b) { b = *this; }	// Only this is illegal
};

For Pub_Derv,Prot_Derv,Priv_ No matter how D inherits B, the member functions and friends of derv can use the conversion from derived classes to base classes, so the member functions of derv are legal for these three classes

For Derived_from_Public,Derived_from_Protected,Derived_ from_ For private, if D inherits B by public or protected, DD (derived class of D) can use the conversion from derived class to base class, so only derived_ from_ Illegal member function of private

20

slightly

21

graphical

2D graphics: Graphics

3D graphics: Graphics

Rectangles: 2D shapes

Circles: 2D shapes

......

Boxes: 3D shapes

Spheres: 3D shapes

......

22

slightly

23

#include <iostream>
#include "Quote.h"
using namespace std;

class Base {
public:
    virtual int fcn() {
        cout << "Base::fcn()\n";
        return 0;
    }
};

class D1 : public Base {
public:
    virtual int fcn() override {
        cout << "D1::fcn()\n";
        return 0;
    }
};

class D2 : public D1 {
public:
    virtual int fcn() override {
        cout << "D2::fcn()\n";
        return 0;
    }
};

int main() {
    Base bobj;
    D1 d1obj;
    D2 d2obj;

    Base *bp1 = &bobj, *bp2 = &d1obj, *bp3 = &d2obj;
    bp1->fcn();
    bp2->fcn();
    bp3->fcn();
    return 0;
}

Operation results:

Base::fcn()
D1::fcn()
D2::fcn()

24

A base class usually needs to define a virtual destructor. Virtual destructors can ensure that the compiler executes the correct version of the destructor (for example, when the static type of a pointer is inconsistent with the dynamic type of the object).

25

Because disc can be foreseen_ Quote will have its own derived class, if the default constructor is removed, because we are Disc_quote defines a custom constructor that accepts four parameters, so the default constructor is deleted, disc_ Derived classes of quote, such as bulk_ The default constructor of quote will also be deleted because Bulk_quote's disc_ The quote base class part cannot be constructed.

26

Quote.h:

#pragma once
#include <iostream>
using std::ostream;
using std::cout;
using std::endl;
#include <string>
using std::string;
#include <utility>
using std::pair;

/*=============================================
					Quote
=============================================*/
class Quote {
public:
	//Quote() = default;
	Quote() : bookNo(""), price(0.0) {
		printf("Quote constructor\n");
	}
	//Quote(const Quote& rhs) = default;
	Quote(const Quote& rhs) : bookNo(rhs.bookNo), price(rhs.price) {
		printf("Quote copy constructor\n");
	}
	//Quote(Quote&& rhs) = default;
	Quote(Quote&& rhs) noexcept :
		bookNo(std::move(rhs.bookNo)), price(std::move(rhs.price)) {
		printf("Quote move constructor\n");
	}
	//Quote& operator=(const Quote& rhs) = default;
	Quote& operator=(const Quote& rhs) {
		printf("Quote copy assignment\n");
		bookNo = rhs.bookNo;
		price = rhs.price;
		return *this;
	}
	//Quote& operator=(Quote&& rhs) = default;
	Quote& operator=(Quote&& rhs) noexcept {
		printf("Quote move assignment\n");
		bookNo = rhs.bookNo;
		price = rhs.price;
		return *this;
	}
	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;
	virtual ~Quote() {
		printf("Quote deconstructor\n");
	}

	virtual void debug() const {
		cout << "bookNo: " << bookNo
			<< "\nprice: " << price << endl;
	}

private:
	string bookNo;
protected:
	double price = 0.0;
};

double printTotal(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;
}

/*=============================================
				Disc_quote
=============================================*/
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) { }
	//virtual ~Disc_quote() = default;
	virtual ~Disc_quote() {
		printf("Disc_quote deconstructor\n");
	}
	
	virtual double net_price(size_t) const = 0;
	pair<size_t, double> discount_policy() const {
		return { quantity, discount };
	}

protected:
	size_t quantity = 0;
	double discount = 0.0;
};

/*=============================================
				Bulk_quote
=============================================*/
class Bulk_quote : public Disc_quote {
public:
	//Bulk_quote() = default;
	Bulk_quote() : Disc_quote(), min_qty(0), discount(0.0) {
		printf("Bulk_quote constructor\n");
	}
	//Bulk_quote(const Bulk_quote& rhs) = default;
	Bulk_quote(const Bulk_quote& rhs) :
		Disc_quote(rhs), min_qty(rhs.min_qty), discount(rhs.discount) {
		printf("Bulk_quote copy constructor\n");
	}
	//Bulk_quote(Bulk_quote&& rhs) = default;
	Bulk_quote(Bulk_quote&& rhs) noexcept :
		Disc_quote(std::move(rhs)),
		min_qty(std::move(rhs.min_qty)), discount(std::move(rhs.discount)) {
		printf("Bulk_quote move constructor\n");
	}
	//Bulk_quote& operator=(const Bulk_quote& rhs) = default;
	Bulk_quote& operator=(const Bulk_quote& rhs) {
		printf("Bulk_quote copy assignment\n");
		Disc_quote::operator=(rhs);
		min_qty = rhs.min_qty;
		discount = rhs.discount;
		return *this;
	}
	//Bulk_quote& operator=(Bulk_quote&& rhs) = default;
	Bulk_quote& operator=(Bulk_quote&& rhs) noexcept {
		printf("Bulk_quote move assignment\n");
		Disc_quote::operator=(std::move(rhs));
		min_qty = rhs.min_qty;
		discount = rhs.discount;
		return *this;
	}
	//virtual ~Bulk_quote() = default;
	virtual ~Bulk_quote() {
		printf("Bulk_quote deconstructor\n");
	}
	Bulk_quote(const string& book, double p, size_t qty, double disc) :
		Disc_quote(book, p, qty, disc) { }
	double net_price(size_t) const override;

	virtual void debug() const override {
		cout << "min_qty: " << min_qty
			<< "\ndiscount: " << discount << endl;
	}

private:
	size_t min_qty = 0;
	double discount = 0.0;
};

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

CppPrimerCh15.cpp:

#include <iostream>
#include "Quote.h"
using namespace std;

int main() {
    Quote b1;
    Quote b2(b1);
    Quote b3(std::move(b1));
    b1 = b2;
    b1 = std::move(b2);
    Bulk_quote d1;
    Bulk_quote d2(d1);
    Bulk_quote d3(std::move(d1));
    d1 = d2;
    d1 = std::move(d2);
    return 0;
}

Operation results:

Quote move constructor
Quote copy assignment
Quote move assignment
Quote constructor
Bulk_quote constructor
Quote copy constructor
Bulk_quote copy constructor
Quote copy constructor
Bulk_quote move constructor
Bulk_quote copy assignment
Quote copy assignment
Bulk_quote move assignment
Quote copy assignment
Bulk_quote deconstructor
Disc_quote deconstructor
Quote deconstructor
Bulk_quote deconstructor
Disc_quote deconstructor
Quote deconstructor
Bulk_quote deconstructor
Disc_quote deconstructor
Quote deconstructor
Quote deconstructor
Quote deconstructor
Quote deconstructor

27

Add in class

using Disc_quote::Disc_quote;

Posted by Blondy on Wed, 13 Oct 2021 06:09:44 -0700