《C++primer(第五版)》学习之路-第十五章:面向对象程序设计

 声明:版权所有,转载请标明出处,请勿用于商业用途。  联系信箱:[email protected]


15.1 OOP:概述


1.面向对象程序设计的核心思想是数据抽象,继承和动态绑定。通过使用数据抽象,我们可以将类的接口与实现分离;使用继承,可以定义相似的类型并对其相似关系建模;使用动态绑定,可以在一定程度上忽略相似类型类型的区别,而以统一的方式使用它们的对象。


2.通过继承联系在一起的类构成一种层次关系。通常在层次关系的根部有一个基类,其他类则直接或间接地从基类继承而来,这些继承得到的类称为派生类。基类负责定义在层次关系中所有类共同拥有的成员,而每个派生类定义各自特有的成员。


15.2 定义基类和派生类


1.派生类必须通过使用类派生列表明确指出它是从哪个基类继承而来的。类派生列表的形式是:首先是一个冒号,后面紧跟以逗号分隔的基类列表,其中每个基类前面可以有以下三种访问说明符的一个:public,protected或者private。


2.一个类是基类,同时它也可以是一个派生类:

class Base{}

class D1:public Base{}

class D2:public D1{}

在这个继承关系中,Base是D1的直接基类,同时是D2的间接基类。直接基类出现在派生列表中,而间接基类由派生类通过其直接基类继承而来。


3.表达式的静态类型在编译时总是已知的,它是变量声明时的类型或表达式生成的类型;动态类型则是变量或表达式表示的内存中的对象的类型。动态类型直到运行时才可知。


15.3 虚函数


1.

override关键字说明派生类函数覆盖基类的虚函数

final关键字不允许之后任何尝试覆盖该函数的操作

override和final说明符出现在形参列表以及尾置返回类型之后。


15.4 抽象基类


1.我们通过在函数体的位置(即在声明语句的分号之前)书写=0就可以将一个虚函数说明为纯虚函数。其中,=0只能出现在类内部的虚函数声明语句处。


2.含有(或者未经覆盖直接继承)纯虚函数的类是抽象基类。抽象基类负责定义接口,而后续的其他类可以覆盖该接口。我们不能(直接)创建一个抽象基类的对象。


15.5 访问控制与继承


1.

protected说明符可以看做是public和private中和后的产物

⑴和私有成员类似,受保护的成员对于类的用户来说是不可访问的

⑵和公有成员类似,受保护的成员对于派生类的成员和友元来说是可访问的。

⑶派生类的成员或友元只能通过派生类对象来访问基类的受保护成员。派生类对于一个基类对象中的受保护成员没有任何访问特权。


2.派生访问说明符对于派生类的成员(及友元)能否访问其直接基类的成员没有什么影响。对基类成员的访问权限只与积累中的访问说明符有关。派生访问说明符的目的是控制派生类用户(包括派生类的派生类在内)对于基类成员的访问权限。


3.派生类向基类的转换是否可访问又使用该转换的代码决定,同时派生类的访问说明符也会有想象。假定D继承自B:

⑴只有当D公有地继承B时,用户代码才能使用派生类向基类的转换:如果D继承自B的方式时受保护的或者私有的,则用户代码不能使用该转换。

⑵不论D以什么方式继承B,D的成员函数和友元都能使用派生类向基类的转换;派生类向其直接基类的类型转换对于派生类的成员和友元来说永远是可访问的。

⑶如果D继承B的方式是共有的或者受保护的,则D的派生类的成员和友元可以使用D向B的类型转换;反之,如果D继承B的方式是私有的,则不能使用。


4.就像友元关系不能传递一样,友元关系同样也不能继承。基类的友元在访问派生类成员时不具有特殊性,类似的,派生类的友元也不能随意访问基类的成员。


5.通过在类的内部使用using声明语句,我们可以将该类的直接或间接基类中的任何可访问成员(例如,非私有成员)标记出来。using声明语句中名字的访问权限由该using声明语句之前的访问说明符来决定。也就是说,如果一条using声明语句出现在类的private部分,则改名字只能被类的成员和友元访问;如果using声明语句位于public部分,则类的所有用户都能访问它;如果using声明语句位于protected部分,则该名字对于成员、友元和派生类是可访问的。

派生类只能为那些它可以访问的名字提供using声明。


15.6 继承中的类作用域


1.声明在内层作用域的函数并不会重载声明在外层作用域的函数。因此,定义派生类中的函数也不会重载其基类中的成员。和其他作用域一样,如果派生类(即内层作用域)的成员与基类(即外层作用域)的某个成员同名,则派生类在其作用域内隐藏该基类成员。即使派生类成员和基类成员的形参列表不一致,基类成员也仍然会被隐藏掉。


15.7 构造函数与拷贝控制


1.通常情况下,using声明语句只是令某个名字在当前作用域内可见。而当作用域构造函数时,using声明语句将令编译器产生代码。对于基类的每个构造函数,编译器都生成一个与之对应的派生类构造函数。换句话说,对于基类的每个构造函数,编译器都在派生类中生成一个形参列表完全相同的构造函数。

这些编译器生成的构造函数形如:

derived(parms):base(args){}

其中derived是派生类的名字,base是基类的名字,parms是构造函数的形参列表,args将派生类构造函数的形参传递给基类的构造函数。


PS:部分练习答案


练习15.3

#ifndef QUOTE_H
#define QUOTE_H

#include 

class Quote
{
	public:
		Quote() = default;
		Quote(const std::string &b, double p) :	bookNo(b), price(p) { }

		std::string isbn() const
		{
			return bookNo;
		}
		virtual double  net_price(std::size_t n) const
		{
			return n * price;
		}

		virtual ~Quote() = default;

	private:
		std::string bookNo;

	protected:
		double  price = 0.0;

};

#endif
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;
}

练习15.5 & 15.6

bulk_quote.h

#ifndef BULK_QUOTE_H
#define BULK_QUOTE_H
#include "quote.h"

class Bulk_quote : public Quote
{
	public:
		Bulk_quote() = default;
		Bulk_quote(const std::string& b, double p, std::size_t q, double disc) : Quote(b,p), min_qty(q), discount(disc)  {}

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

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

#endif

bulk_quote.cpp

#include "bulk_quote.h"

double Bulk_quote::net_price(std::size_t n) const
{
	return n * price * ( n >= min_qty ? 1 - discount : 1);
}

main.cpp

#include 
#include 

#include "quote.h"
#include "bulk_quote.h"

double print_total (std::ostream& os, const Quote& item, size_t n);

int main()
{
	//! ex15.6
	Quote q("book", 10.60);
	Bulk_quote bq("book", 10.60, 10, 0.3);

	print_total(std::cout, q, 12);
	print_total(std::cout, bq, 12);

	return 0;
}

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;
}

练习15.7

limit_quote.h

#ifndef LIMIT_QUOTE_H
#define LIMIT_QUOTE_H

#include "quote.h"

class Limit_quote : public Quote
{
	public:
		Limit_quote();
		Limit_quote(const std::string& b, double p, std::size_t max, double disc): Quote(b,p), max_qty(max), discount(disc)    {}

		double net_price(std::size_t n) const override
		{
			return n * price * (n < max_qty ? 1 - discount : 1 );
		}

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

#endif

main.cpp

#include 
#include 

#include "quote.h"
#include "bulk_quote.h"
#include "limit_quote.h"

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()
{
	//! ex15.6
	Quote q("textbook", 10.60);
	Bulk_quote bq("textbook", 10.60, 10, 0.3);
	Limit_quote lq("Bible", 10.60, 10 , 0.3);

	print_total(std::cout, q, 5);
	print_total(std::cout, bq, 5);
	print_total(std::cout ,lq, 5);

	return 0;
}

练习15.11

quote.h

#ifndef QUOTE_H
#define QUOTE_H

#include 
#include 

class Quote
{
	public:
		Quote() = default;
		Quote(const std::string &b, double p) : bookNo(b), price(p) { }

		std::string     isbn() const
		{
			return bookNo;
		}
		virtual double  net_price(std::size_t n) const
		{
			return n * price;
		}
		virtual void    debug() const;

		virtual ~Quote() = default;

	private:
		std::string bookNo;

	protected:
		double  price = 0.0;

};

#endif

quote.cpp

#include "quote.h"

void Quote::debug() const
{
	std::cout << "data members of this class:\n"
	          << "bookNo= " <bookNo << " "
	          << "price= " <price<< " ";
}

练习15.15 & 15.16 & 15.17

quote.h

#ifndef QUOTE_H
#define QUOTE_H

#include 
#include 

class Quote
{
	public:
		Quote() = default;
		Quote(const std::string &b, double p) : bookNo(b), price(p) { }

		std::string isbn() const
		{
			return bookNo;
		}
		virtual double  net_price(std::size_t n) const
		{
			return n * price;
		}
		virtual void    debug() const;

		virtual ~Quote() = default;

	private:
		std::string bookNo;

	protected:
		double  price = 0.0;

};

#endif

quote.cpp

#include "quote.h"

void Quote::debug() const
{
	std::cout << "bookNo= " <bookNo << " "
	          << "price= " <price<< " ";
}

disc_quote.h

#ifndef DISC_QUOTE_H
#define DISC_QUOTE_H

#include "quote.h"
class Disc_quote : public Quote
{
	public:
		Disc_quote();
		Disc_quote(const std::string& b, double p, std::size_t q, double d) : Quote(b, p), quantity(q), discount(d)   { }

		virtual double net_price(std::size_t n) const override = 0;

	protected:
		std::size_t quantity;
		double discount;
};

#endif

disc_quote.cpp

#include "disc_quote.h"

limit_quote.h

#ifndef LIMIT_QUOTE_H
#define LIMIT_QUOTE_H

#include "disc_quote.h"

class Limit_quote : public Disc_quote
{
	public:
		Limit_quote() = default;
		Limit_quote(const std::string& b, double p, std::size_t max, double disc): Disc_quote(b,p,max,disc)  {   }

		double net_price(std::size_t n) const override
		{
			return n * price * (n < quantity ? 1 - discount : 1 );
		}

		void debug() const override;
};

#endif

limit_quote.cpp

#include "limit_quote.h"


void Limit_quote::debug() const
{
	Quote::debug();
	std::cout << "max_qty= " << quantity << " "
	          << "discount= " << discount<< " ";
}

bulk_quote.h

#ifndef BULK_QUOTE_H
#define BULK_QUOTE_H
#include "disc_quote.h"

class Bulk_quote : public Disc_quote
{
	public:
		Bulk_quote() = default;
		Bulk_quote(const std::string& b, double p, std::size_t q, double disc) : Disc_quote(b,p,q,disc) {   }

		double net_price(std::size_t n) const override;
		void  debug() const override;


};

#endif

bulk_quote.cpp

#include "bulk_quote.h"

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

void Bulk_quote::debug() const
{
	Quote::debug();
	std::cout << "min_qty= " << quantity << " "
	          << "discount= " << discount<< " ";
}

练习15.18 & 15.19 & 15.20

#include 
#include 

#include "quote.h"
#include "bulk_quote.h"
#include "limit_quote.h"
#include "disc_quote.h"

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
{
	void memfcn(Base &b)
	{
		b = *this;
	}
};
struct Priv_Derv    : private   Base
{
	void memfcn(Base &b)
	{
		b = *this;
	}
};
struct Prot_Derv    : protected Base
{
	void memfcn(Base &b)
	{
		b = *this;
	}
};

struct Derived_from_Public      : public Pub_Derv
{
	void memfcn(Base &b)
	{
		b = *this;
	}
};
struct Derived_from_Private     : public Priv_Derv
{
	//void memfcn(Base &b) { b = *this; }
};
struct Derived_from_Protected   : public Prot_Derv
{
	void memfcn(Base &b)
	{
		b = *this;
	}
};

int main()
{
	Pub_Derv d1;
	Base *p = &d1;

	Priv_Derv d2;
	//p = &d2;

	Prot_Derv d3;
	//p = &d3;

	Derived_from_Public dd1;
	//p = &dd1;

	Derived_from_Private dd2;
	//p =& dd2;

	Derived_from_Protected dd3;
	//p = &dd3;


	return 0;
}

练习15.21 & 22

#include 
#include 

#include "quote.h"
#include "bulk_quote.h"
#include "limit_quote.h"
#include "disc_quote.h"

//! just for 2D shape
class Shape
{
	public:
		typedef std::pair    Coordinate;

		Shape() = default;
		Shape(const std::string& n) :
			name(n) { }

		virtual double area()       const = 0;
		virtual double perimeter()  const = 0;

		virtual ~Shape() = default;
	private:
		std::string name;
};

class Rectangle : public Shape
{
	public:
		Rectangle() = default;
		Rectangle(const std::string& n,
		          const Coordinate& a,
		          const Coordinate& b,
		          const Coordinate& c,
		          const Coordinate& d) :
			Shape(n), a(a), b(b), c(c), d(d) { }

		~Rectangle() = default;

	protected:
		Coordinate  a;
		Coordinate  b;
		Coordinate  c;
		Coordinate  d;
};

class Square : public Rectangle
{
	public:
		Square() = default;
		Square(const std::string& n,
		       const Coordinate& a,
		       const Coordinate& b,
		       const Coordinate& c,
		       const Coordinate& d) :
			Rectangle(n,a,b,c,d) { }

		~Square() = default;
};


int main()
{

	return 0;
}

练习15.26

quote.h

#ifndef QUOTE_H
#define QUOTE_H

#include 
#include 

class Quote
{
		friend bool operator !=(const Quote& lhs, const Quote& rhs);
	public:
		Quote()
		{
			std::cout << "default constructing Quote\n";
		}
		Quote(const std::string &b, double p) : bookNo(b), price(p)
		{
			std::cout << "Quote : constructor taking 2 parameters\n";
		}

		//! copy constructor
		Quote(const Quote& q) : bookNo(q.bookNo), price(q.price)
		{
			std::cout << "Quote: copy constructing\n";
		}

		//! move constructor
	Quote(Quote&& q) noexcept :
		bookNo(std::move(q.bookNo)), price(std::move(q.price))
		{
			std::cout << "Quote: move constructing\n";
		}

		//! copy =
		Quote& operator =(const Quote& rhs)
		{
			if(*this != rhs)
			{
				bookNo = rhs.bookNo;
				price  = rhs.price;
			}
			std::cout << "Quote: copy =() \n";

			return *this;
		}

		//! move =
		Quote& operator =(Quote&& rhs)  noexcept
		{
			if(*this != rhs)
			{
				bookNo = std::move(rhs.bookNo);
				price  = std::move(rhs.price);
			}
			std::cout << "Quote: move =!!!!!!!!! \n";

			return *this;
		}

		std::string     isbn() const
		{
			return bookNo;
		}
		virtual double  net_price(std::size_t n) const
		{
			return n * price;
		}
		virtual void    debug() const;

		virtual ~Quote()
		{
			std::cout << "destructing Quote\n";
		}

	private:
		std::string bookNo;

	protected:
		double  price = 10.0;
};

bool inline operator !=(const Quote& lhs, const Quote& rhs)
{
	return lhs.bookNo != rhs.bookNo && lhs.price  != rhs.price;
}

#endif

quote.cpp

#include "quote.h"

void Quote::debug() const
{
	std::cout << "bookNo= " <bookNo << " "
	          << "price= " <price<< " ";
}

disc_quote.h

#ifndef DISC_QUOTE_H
#define DISC_QUOTE_H

#include "quote.h"
class Disc_quote : public Quote
{
		friend bool operator !=(const Disc_quote& lhs, const Disc_quote& rhs);
	public:
		Disc_quote()
		{
			std::cout << "default constructing Disc_quote\n";
		}

		Disc_quote(const std::string& b, double p, std::size_t q, double d) : Quote(b, p), quantity(q), discount(d)
		{
			std::cout << "Disc_quote : constructor taking 4 parameters.\n";
		}

		//! copy constructor
		Disc_quote(const Disc_quote& dq) : Quote(dq), quantity(dq.quantity), discount(dq.discount)
		{
			std::cout << "Disc_quote : copy constructor.\n";
		}

		//! move constructor
	Disc_quote(Disc_quote&& dq) noexcept :
		Quote(std::move(dq)), quantity(std::move(dq.quantity)), discount(std::move(dq.discount))
		{
			std::cout << "Disc_quote : move constructor.\n";
		}

		//! copy =()
		Disc_quote& operator =(const Disc_quote& rhs)
		{
			Quote::operator =(rhs);
			this->quantity = rhs.quantity;
			this->discount = rhs.discount;

			std::cout << "Disc_quote : copy =()\n";

			return *this;
		}

		//! move =()
		Disc_quote& operator =(Disc_quote&& rhs) noexcept
		{
			if (*this != rhs)
			{
				Quote::operator =(std::move(rhs));
				this->quantity = std::move(rhs.quantity);
				this->discount = std::move(rhs.discount);
			}
			std::cout << "Disc_quote : move =()\n";

			return *this;
		}

		virtual double net_price(std::size_t n) const override = 0;

		~Disc_quote()
		{
			std::cout << "destructing Dis_quote\n";
		}

	protected:
		std::size_t quantity = 3;
		double discount = 0.0;
};

bool inline operator !=(const Disc_quote& lhs, const Disc_quote& rhs)
{
	return Quote(lhs) != Quote(rhs) && lhs.quantity != rhs.quantity && lhs.discount != rhs.discount;
}

#endif

disc_quote.cpp

#include "disc_quote.h"

bulk_quote.h

#ifndef BULK_QUOTE_H
#define BULK_QUOTE_H
#include "disc_quote.h"

class Bulk_quote : public Disc_quote
{

	public:
		Bulk_quote()
		{
			std::cout << "default constructing Bulk_quote\n";
		}
		Bulk_quote(const std::string& b, double p, std::size_t q, double disc) :
			Disc_quote(b,p,q,disc)
		{
			std::cout << "Bulk_quote : constructor taking 4 parameters\n";
		}

		//! copy constructor
		Bulk_quote(const Bulk_quote& bq) : Disc_quote(bq)
		{
			std::cout << "Bulk_quote : copy constructor\n";
		}

		//! move constructor
		Bulk_quote(Bulk_quote&& bq) : Disc_quote(std::move(bq)) noexcept
		{
			std::cout << "Bulk_quote : move constructor\n";
		}

		//! copy =()
		Bulk_quote& operator =(const Bulk_quote& rhs)
		{
			Disc_quote::operator =(rhs);
			std::cout << "Bulk_quote : copy =()\n";

			return *this;
		}


		//! move =()
		Bulk_quote& operator =(Bulk_quote&& rhs) noexcept
		{
			Disc_quote::operator =(std::move(rhs));
			std::cout << "Bulk_quote : move =()\n";

			return *this;
		}

		double net_price(std::size_t n) const override;
		void  debug() const override;

		~Bulk_quote() override
		{
			std::cout << "destructing Bulk_quote\n";
		}
};



#endif

bulk_quote.cpp

#include "bulk_quote.h"

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

void Bulk_quote::debug() const
{
	Quote::debug();
	std::cout << "min_qty= " << quantity << " "
	          << "discount= " << discount<< " ";
}

limit_ quote.h

#ifndef LIMIT_QUOTE_H
#define LIMIT_QUOTE_H

#include "disc_quote.h"

class Limit_quote : public Disc_quote
{
	public:
		Limit_quote() = default;
		Limit_quote(const std::string& b, double p, std::size_t max, double disc): Disc_quote(b,p,max,disc)  {   }

		double net_price(std::size_t n) const override
		{
			return n * price * (n < quantity ? 1 - discount : 1 );
		}

		void debug() const override;
};

#endif

limit_ quote.cpp

#include "limit_quote.h"


void Limit_quote::debug() const
{
	Quote::debug();
	std::cout << "max_qty= " << quantity << " "
	          << "discount= " << discount<< " ";
}

main.cpp

#include 
#include 

#include "quote.h"
#include "bulk_quote.h"
#include "limit_quote.h"
#include "disc_quote.h"


int main()
{
	Bulk_quote bq1;
	Bulk_quote bq2("ss",2.05,12,0.3);
	bq2 = std::move(bq2);


	return 0;
}

练习15.27

#ifndef BULK_QUOTE_H
#define BULK_QUOTE_H
#include "disc_quote.h"

class Bulk_quote : public Disc_quote
{

	public:
		Bulk_quote()
		{
			std::cout << "default constructing Bulk_quote\n";
		}
		
		using Disc_quote::Disc_quote;

		//! copy constructor
		Bulk_quote(const Bulk_quote& bq) : Disc_quote(bq)
		{
			std::cout << "Bulk_quote : copy constructor\n";
		}

		//! move constructor
		Bulk_quote(Bulk_quote&& bq) : Disc_quote(std::move(bq))
		{
			std::cout << "Bulk_quote : move constructor\n";
		}

		//! copy =()
		Bulk_quote& operator =(const Bulk_quote& rhs)
		{
			Disc_quote::operator =(rhs);
			std::cout << "Bulk_quote : copy =()\n";

			return *this;
		}


		//! move =()
		Bulk_quote& operator =(Bulk_quote&& rhs)
		{
			Disc_quote::operator =(std::move(rhs));
			std::cout << "Bulk_quote : move =()\n";

			return *this;
		}

		double net_price(std::size_t n) const override;
		void  debug() const override;

		~Bulk_quote() override
		{
			std::cout << "destructing Bulk_quote\n";
		}
};

#endif

练习15.28 & 15.29

#include 
#include 
#include 
#include 

#include "quote.h"
#include "bulk_quote.h"
#include "limit_quote.h"
#include "disc_quote.h"


int main()
{
	/**
	 * @brief ex15.28   outcome == 9090
	 */
	std::vector v;
	for(unsigned i =1; i != 10; ++i)
		v.push_back(Bulk_quote("sss", i * 10.1, 10, 0.3));

	double total = 0;
	for (const auto& b : v)
	{
		total += b.net_price(20);
	}
	std::cout << total << std::endl;

	std::cout << "======================\n\n";

	/**
	 * @brief ex15.29   outccome == 6363
	 */
	std::vector> pv;

	for(unsigned i =1; i != 10; ++i)
		pv.push_back(std::make_shared(Bulk_quote("sss", i * 10.1, 10, 0.3)));

	double total_p = 0;
	for (auto p : pv)
	{
		total_p +=  p->net_price(20);
	}
	std::cout << total_p << std::endl;

	return 0;

}

练习15.35 & 15.38

StrBlob.h

#ifndef STRBLOB_H
#define STRBLOB_H

#include 
#include 
#include 
#include 
#include 

class StrBlobPtr;

class StrBlob
{
		friend class StrBlobPtr;
	public:
		typedef std::vector::size_type size_type;

		// constructors
		StrBlob() : data(std::make_shared>()) { }
		StrBlob(std::initializer_list il);

		// size operations
		size_type size() const
		{
			return data->size();
		}
		bool empty() const
		{
			return data->empty();
		}

		// add and remove elements
		void push_back(const std::string &t)
		{
			data->push_back(t);
		}
		void pop_back();

		// element access
		std::string& front();
		std::string& back();

		// interface to StrBlobPtr
		StrBlobPtr begin();  // can't be defined until StrBlobPtr is
		StrBlobPtr end();
	private:
		std::shared_ptr> data;
		// throws msg if data[i] isn't valid
		void check(size_type i, const std::string &msg) const;
};

// constructor
inline
StrBlob::StrBlob(std::initializer_list il):
	data(std::make_shared>(il)) { }

// StrBlobPtr throws an exception on attempts to access a nonexistent element
class StrBlobPtr
{
		friend bool eq(const StrBlobPtr&, const StrBlobPtr&);
	public:
		StrBlobPtr(): curr(0) { }
		StrBlobPtr(StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) { }

		StrBlobPtr(const StrBlob &a, const size_t sz = 0) : wptr(a.data), curr(sz) { }

		std::string& deref() const;
		StrBlobPtr& incr();
		StrBlobPtr& decr();
	private:
		// check returns a shared_ptr to the vector if the check succeeds
		std::shared_ptr> check(std::size_t, const std::string&) const;

		// store a weak_ptr, which means the underlying vector might be destroyed
		std::weak_ptr> wptr;
		std::size_t curr;      // current position within the array
};

inline std::string& StrBlobPtr::deref() const
{
	auto p = check(curr, "dereference past end");
	return (*p)[curr];  // (*p) is the vector to which this object points
}

inline std::shared_ptr> StrBlobPtr::check(std::size_t i, const std::string &msg) const
{
	auto ret = wptr.lock();   // is the vector still around?
	if (!ret)
		throw std::runtime_error("unbound StrBlobPtr");

	if (i >= ret->size())
		throw std::out_of_range(msg);
	return ret; // otherwise, return a shared_ptr to the vector
}

// prefix: return a reference to the incremented object
inline StrBlobPtr& StrBlobPtr::incr()
{
	// if curr already points past the end of the container, can't increment it
	check(curr, "increment past end of StrBlobPtr");
	++curr;       // advance the current state
	return *this;
}

inline StrBlobPtr& StrBlobPtr::decr()
{
	// if curr is zero, decrementing it will yield an invalid subscript
	--curr;       // move the current state back one element}
	check(-1, "decrement past begin of StrBlobPtr");
	return *this;
}

// begin and end members for StrBlob
inline StrBlobPtr StrBlob::begin()
{
	return StrBlobPtr(*this);
}

inline StrBlobPtr StrBlob::end()
{
	auto ret = StrBlobPtr(*this, data->size());
	return ret;
}

// named equality operators for StrBlobPtr
inline bool eq(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
	auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
	// if the underlying vector is the same
	if (l == r)
		// then they're equal if they're both null or
		// if they point to the same element
		return (!r || lhs.curr == rhs.curr);
	else
		return false; // if they point to difference vectors, they're not equal
}

inline bool neq(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
	return !eq(lhs, rhs);
}
#endif
textquery.h

#ifndef TEXTQUERY_H
#define TEXTQUERY_H

#include "StrBlob.h"
#include 
#include 
#include 
#include 
#include 

class QueryResult;

class TextQuery
{
	public:
		typedef StrBlob::size_type line_no;

		//! constructor
		TextQuery(std::ifstream& fin);

		//! query operation
		QueryResult query(const std::string&) const;

	private:
		//! data members
		StrBlob file;

		std::map>> wordMap;

};

#endif
textquery.cpp

#include "textquery.h"
#include "queryresult.h"
#include 
#include 
#include 

TextQuery::TextQuery(std::ifstream &fin) : file(StrBlob()), wordMap(std::map>>())
{
	std::string line;

	//! each line
	while(std::getline(fin, line))
	{
		file.push_back(line);
		int n = file.size() - 1;    //! the current line number

		//! each word
		std::stringstream lineSteam(line);
		std::string word;
		while(lineSteam >> word)
		{
			std::shared_ptr>& sp_lines = wordMap[word];
			//! if null
			if(!sp_lines)
			{
				sp_lines.reset(new std::set);
			}
			sp_lines->insert(n);
		}
	}
}

QueryResult TextQuery::query(const std::string &sought) const
{
	static std::shared_ptr> noData(new std::set);

	auto iter = wordMap.find(sought);
	if(iter == wordMap.end())
		return QueryResult(sought, noData, file);
	else
		return QueryResult(sought, iter->second, file);
}
queryresult.h

#ifndef QUERYRESULT_H
#define QUERYRESULT_H

#include 
#include 
#include 
#include 
#include 
#include "textquery.h"

class QueryResult
{
		friend std::ostream& print(std::ostream&, const QueryResult&);

	public:
		//! constructor
		QueryResult(std::string s, std::shared_ptr> sp_l, StrBlob f) :
			sought(s), sp_lines(sp_l), file(f) { }

		//! added for ex12.33
		const StrBlob& get_file() const
		{
			return file;
		}

		std::set::iterator begin()
		{
			return sp_lines->begin();
		}

		std::set::iterator end()
		{
			return sp_lines->end();
		}

	private:
		//! three data members
		std::string sought;
		std::shared_ptr> sp_lines;
		StrBlob file;

};

std::ostream& print(std::ostream&, const QueryResult &);
#endif
queryresult.cpp

#include "queryresult.h"

std::ostream
&print(std::ostream &os, const QueryResult &qr)
{
	os << qr.sought << " occurs " << qr.sp_lines->size() << " " << "times"   <<  "\n";

	//! print each line in which the word appears
	for ( auto &index : *qr.sp_lines)
	{
		os << "\t(line " << index + 1 << ") ";
		const StrBlobPtr wp(qr.file, index);
		os << wp.deref() << "\n";
	}
	return os;

}
query_base.h

#ifndef QUERY_BASE_H
#define QUERY_BASE_H
#include "textquery.h"
#include "queryresult.h"

class Query_base
{
		friend class Query;
	protected:
		using line_no = TextQuery::line_no; //  used in the eval function
		virtual ~Query_base() = default;

	private:
		//! returns QueryResult that matches this query
		virtual QueryResult eval(const TextQuery&) const = 0;

		//! a string representation of this query
		virtual std::string rep() const = 0;
};

#endif

query_base.cpp

 #include "query_base.h"
word query.h

#ifndef WORDQUERY_H
#define WORDQUERY_H

#include "query_base.h"

class WordQuery : public Query_base
{
		//! class Query uses the WordQuery constructor
		friend class Query;
		WordQuery(const std::string& s): query_word(s)
		{
			std::cout << "WordQuery::WordQuery(" + s + ")\n";
		}


		//! virtuals:
		QueryResult eval(const TextQuery& t) const override
		{
			return t.query(query_word);
		}
		std::string rep() const override
		{
			std::cout << "WodQuery::rep()\n";
			return query_word;
		}


		std::string query_word;
};

#endif
wordquery.cpp

 #include "wordquery.h"
query.h

#ifndef QUERY_H
#define QUERY_H

#include 
#include 
#include 
#include "query_base.h"
#include "queryresult.h"
#include "textquery.h"
#include "wordquery.h"

class Query
{
		friend Query operator~(const Query&);
		friend Query operator|(const Query&, const Query&);
		friend Query operator&(const Query&, const Query&);
	public:
		//! build a new WordQuery
		Query(const std::string& s) : q(new WordQuery(s))
		{
			std::cout << "Query::Query(const std::string& s) where s="+s+"\n";
		}

		//! interface functions: call the corresponding Query_base operatopns
		QueryResult eval(const TextQuery& t) const
		{
			return q->eval(t);
		}
		std::string rep() const
		{
			std::cout << "Query::rep() \n";
			return q->rep();
		}

	private:
		//! constructor only for friends
		Query(std::shared_ptr query) :
			q(query)
		{
			std::cout << "Query::Query(std::shared_ptr query)\n";
		}
		std::shared_ptr q;
};

inline std::ostream&
operator << (std::ostream& os, const Query& query)
{
	//! make a virtual call through its Query_base pointer to rep();
	return os << query.rep();
}

#endif
query.cpp

 #include "query.h"
binary query.h

#ifndef BINARYQUERY_H
#define BINARYQUERY_H

#include "query_base.h"
#include "query.h"

class BinaryQuery : public Query_base
{
	protected:
		BinaryQuery(const Query&l, const Query& r, std::string s): lhs(l), rhs(r), opSym(s)
		{
			std::cout << "BinaryQuery::BinaryQuery()  where s=" + s + "\n";
		}

		std::string rep() const override
		{
			std::cout << "BinaryQuery::rep()\n";
			return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")";
		}

		Query lhs, rhs;
		std::string opSym;
};

#endif
binaryquery.cpp

 #include "binaryquery.h"
not query.h

#ifndef NOTQUERY_H
#define NOTQUERY_H
#include "query_base.h"
#include "query.h"

class NotQuery : public Query_base
{
		friend Query operator~(const Query& operand);
		NotQuery(const Query& q): query(q)
		{
			std::cout << "NotQuery::NotQuery()\n";
		}

		//! virtuals:
		std::string rep() const override
		{
			std::cout << "NotQuery::rep()\n";
			return "~(" + query.rep() + ")";
		}

		QueryResult eval(const TextQuery &) const override;

		Query query;
};

inline Query operator~(const Query& operand)
{
	return std::shared_ptr(new NotQuery(operand));
}

#endif
not query.cpp

 #include "notquery.h"
and query.h

#ifndef ANDQUERY_H
#define ANDQUERY_H


#include "binaryquery.h"

class AndQuery : public BinaryQuery
{
		friend Query operator&(const Query&, const Query&);
		AndQuery(const Query& left, const Query& right): BinaryQuery(left,right, "&")
		{
			std::cout << "AndQuery::AndQuery()\n";
		}

		QueryResult eval(const TextQuery &) const override
		{
			// this is just a placeholder rather than the real definition
		}
};

inline Query operator& (const Query& lhs, const Query& rhs)
{
	return std::shared_ptr(new AndQuery(lhs,rhs));
}

#endif

andquery.cpp

 #include "andquery.h"
or query.h

#ifndef ORQUERY_H
#define ORQUERY_H

#include "binaryquery.h"

class OrQuery :public BinaryQuery
{
		friend Query operator|(const Query&, const Query&);
		OrQuery(const Query& left, const Query& right): BinaryQuery(left, right, "|")
		{
			std::cout << "OrQuery::OrQuery\n";
		}

		QueryResult eval(const TextQuery& )const override
		{
			//place holder
		}
};

inline Query operator|(const Query &lhs, const Query& rhs)
{
	return std::shared_ptr(new OrQuery(lhs, rhs));
}

#endif

orquery.cpp

 #include "orquery.h"

main.cpp

#include 
#include 
#include 
#include 
#include 

#include "queryresult.h"
#include "textquery.h"
#include "query_base.h"
#include "query.h"
#include "andquery.h"
#include "orquery.h"



int main()
{
//  ex15.38
//	BinaryQuery a = Query("fiery") & Query("bird");
//	AndQuery b = Query("fiery") & Query("bird");
//	OrQuery c = Query("fiery") & Query("bird");
	return 0;
}



你可能感兴趣的:(《C++primer(第五版)》学习之路-第十五章:面向对象程序设计)