C++程序设计原理与实践 习题答案 第二十章 第20章习题答案

习题要求所设计的函数类和数据图类

Func_Data_Graph.h

#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Graph.h"
#include"../../GUI/Simple_window.h"

using namespace Graph_lib;

namespace Func_Data_Graph {

	template<class VType = double>
	class Scale {
		int cbase;
		VType vbase;
		double scale;
	public:
		Scale(int b, VType v, double s)
			:cbase{ b }, vbase{ v }, scale{ s }{}
		int operator()(VType v) const
		{
			return cbase + round((v - vbase) * scale);
		}
	};

	//-------------------------------------------------------------------

	template<class PrecType = double>
	class Func : public Function {
		Fct fct;
		double r1, r2;
		Point cen;
		int cnt;
		double xs, ys;
		PrecType prec;
	protected:
		void reset();

	public:
		Func(Fct f, double r1, double r2, Point orig, 
			int count = 100, double xscale = 25, double yscale = 25, 
			PrecType prec = PrecType(1));

		void reset_function(Fct f);
		void reset_range(double r1, double r2);
	};

	template<class PrecType>
	Func<PrecType>::Func(Fct f, double r1, double r2, Point orig,
		int count, double xscale, double yscale, PrecType precision)
		: Function(f, r1, r2, orig, count, xscale, yscale),
		fct{ f }, r1{ r1 }, r2{ r2 }, cen{ orig },
		cnt{ count }, xs{ xscale }, ys{ yscale }, prec{ precision}
	{	}

	template<class PrecType>
	void Func<PrecType>::reset()
	{
		PrecType dist = PrecType(r2 - r1) / cnt;
		PrecType r = r1;
		int np = number_of_points();
		int i;
		for (i = 0; i < np; ++i)
		{
			Point p{ cen.x + int(r * xs), cen.y - int(PrecType(fct(r)) * ys) };
			set_point(i, p);
			r += dist;
		}
		for (i = np; i < cnt; ++i)
		{
			add(Point{ cen.x + int(r * xs), cen.y - int(PrecType(fct(r)) * ys) });
			r += dist;
		}
	}

	template<class PrecType>
	void Func<PrecType>::reset_function(Fct f)
	{
		fct = f;
		reset();
	}

	template<class PrecType>
	void Func<PrecType>::reset_range(double rg1, double rg2)
	{
		if (rg2 - rg1 <= 0)
			error("bad graphing range");
		r1 = rg1;
		r2 = rg2;
		reset();
	}


	//------------------------------------------------------------------
	class XY_axis : public Shape {
		//一个XY坐标轴
		Axis x;
		Axis y;
		Point o;	//原点
		int xlen;	//x轴长度
		int ylen;
	public:
		XY_axis(Point oo, int xlength, int ylength, 
			const string & xlab = "x", const string & ylab = "y");
		void draw_lines() const override;
		void move(int dx, int dy) override;
		void set_color(Color c);
		void set_x_label(const string& lab);
		void set_y_label(const string& lab);
	};

	template<typename DataType>
	class Bar : public Graph_lib::Rectangle {
		//带标签的柱状图
	public:
		Bar(Point cen, int width, int height, pair<string, DataType> psd);
		void draw_lines() const override;
		void move(int dx, int dy) override;
		void set_color(Color c);
		
		Text label;	//柱体下面的标签
		Text data;	//柱体上面的数字标识
	};

	template<typename DataType>
	Bar<DataType>::Bar(Point cen, int width, int ytop, pair<string,DataType> psd)
		:Rectangle{ Point{cen.x - int(round(width / 2.0)), ytop},
					Point{cen.x + int(round(width / 2.0)), cen.y} },
		label{ Point{cen.x - int(round(width / 2.0)),cen.y + 15}, psd.first },
		data{ Point{cen.x - int(round(width / 2.0)),ytop - 1}, ""}
	{
		ostringstream oss;
		oss << psd.second;
		data.set_label(oss.str());
	}

	template<typename DataType>
	void Bar<DataType>::draw_lines() const
	{
		Rectangle::draw_lines();
		label.draw();
		data.draw();
	}

	template<typename DataType>
	void Bar< DataType>::move(int dx, int dy)
	{
		Rectangle::move(dx, dy);
		label.move(dx, dy);
		data.move(dx, dy);
	}

	template<typename DataType>
	void Bar<DataType>::set_color(Color c)
	{
		Rectangle::set_color(c);
		label.set_color(c);
		data.set_color(c);
	}

	//---------------------------------------------------------------------

	template<typename DataType>
	//DataType 必须是数字类型
	class Histogram : public Shape {
		vector<pair<string,DataType>> datas;	//(标签,数据)对
		XY_axis xy_axis;		//一个坐标系
		Text title;
		Vector_ref<Bar<DataType>> bars;	//带标签柱形状集

	public:
		Histogram(Point xy, int width, int height,
			const vector<pair<string,DataType>>vdata, const string& title = "");

		void draw_lines() const override;
		void move(int dx, int dy) override;
		
		void set_color_all(Color c);
		void set_fill_color_bars_all(Color c);

		void set_bar_color_by_index(int index, Color c);
		void set_bar_fill_color_by_index(int index, Color c);

		void set_title(const string& tt);
		void set_xaxis_label(const string& xstr);
		void set_yaxis_label(const string& ystr);
		void set_bar_label_by_index(int index, const string& str);
		//...
	};

	//---------------------------------------------------------------------
	template<typename DataType>
	Histogram<DataType>::Histogram(Point xy, int width, int height,
		const vector<pair<string,DataType>> vdata, const string& tt)
		: datas{ vdata },
		xy_axis{ Point{ xy.x, xy.y + height - 15 }, width, height - 30 },
		title{ Point{xy.x + width / 2, xy.y + 14}, tt }
	{
		if (datas.size() == 0)
			return;
		//这里有一个隐含条件,期望datas都是大于零的数
		DataType max{ datas[0].second };
		for (auto pd : datas)
			if (pd.second > max)
				max = pd.second;
		const int space_for_text{ 15 };
		const int axis_ylen = height - 2 * space_for_text;
		const int yorig = xy.y + height - space_for_text;
		const double xscale{ double(width) / (datas.size() + 1) };
		const double yscale{ double(axis_ylen - space_for_text) / max };
		Scale<DataType> xs{ xy.x, 0, xscale };
		Scale<DataType> ys{ yorig, 0, -yscale };

		//计算柱宽,而且每条柱间隔一个柱宽
		const int bar_width = round(double(width) / (2 * datas.size()));
		for (int i = 0; i < datas.size(); ++i)
		{
			bars.push_back(new Bar<DataType>{ Point{xs(i + 1),yorig},bar_width,ys(datas[i].second),datas[i] });
			bars[bars.size() - 1].set_color(Color::black);
			bars[bars.size() - 1].set_fill_color(Color::white);
		}
		xy_axis.set_color(Color::red);
		title.set_color(Color::black);
	}

	template<typename DataType>
	void Histogram<DataType>::draw_lines() const
	{
		xy_axis.draw();
		title.draw();
		for (int i = 0; i < bars.size(); ++i)
			bars[i].draw();
	}

	template<typename DataType>
	void Histogram<DataType>::move(int dx, int dy)
	{
		xy_axis.move(dx, dy);
		title.move(dx, dy);
		for (int i = 0; i < bars.size(); ++i)
			bars[i].move(dx, dy);
	}

	template<typename DataType>
	void Histogram<DataType>::set_color_all(Color c)
	{
		xy_axis.set_color(c);
		title.set_color(c);
		for (int i = 0; i < bars.size(); ++i)
			bars[i].set_color(c);
	}

	template<typename DataType>
	void Histogram<DataType>::set_fill_color_bars_all(Color c)
	{
		for (int i = 0; i < bars.size(); ++i)
			bars[i].set_fill_color(c);
	}

	template<typename DataType>
	void Histogram<DataType>::set_bar_color_by_index(int index, Color c)
	{
		if (index >= bars.size())
			error("Bad index: out of range");
		bars[index].set_color(c);
	}

	template<typename DataType>
	void Histogram<DataType>::set_bar_fill_color_by_index(int index, Color c)
	{
		if (index >= bars.size())
			error("Bad index: out of range");
		bars[index].set_fill_color(c);
	}

	template<typename DataType>
	void Histogram<DataType>::set_title(const string& tt)
	{
		title.set_label(tt);
	}

	template<typename DataType>
	void Histogram<DataType>::set_xaxis_label(const string& xlab)
	{
		xy_axis.set_x_label(xlab);
	}

	template<typename DataType>
	void Histogram<DataType>::set_yaxis_label(const string& ylab)
	{
		xy_axis.set_y_label(ylab);
	}

	template<typename DataType>
	void Histogram<DataType>::set_bar_label_by_index(int index, const string& lab)
	{
		if (index >= bars.size())
			error("Bad index: out of range");
		bars[index].label.set_label(lab);
	}

};

Func_Data_Graph.cpp

#include"Func_Data_Graph.h"

namespace Func_Data_Graph {


	XY_axis::XY_axis(Point oo, int xlength, int ylength,
		const string& xlab, const string& ylab)
		:x{Axis::x, oo, xlength, 0, xlab},
		 y{ Axis::y, oo, ylength, 0, ylab },
		 o{oo}, xlen{xlength},ylen{ylength}
	{
		if (xlen <= 0 || ylen <= 0)
			error("Bad XY Axis: non-positive length of X or Y axis");
	}

	void XY_axis::draw_lines() const
	{
		x.draw();
		y.draw();
	}

	void XY_axis::move(int dx, int dy)
	{
		x.move(dx, dy);
		y.move(dx, dy);
	}

	void XY_axis::set_color(Color c)
	{
		Shape::set_color(c);
		x.set_color(c);
		y.set_color(c);
	}

	void XY_axis::set_x_label(const string& lab)
	{
		x.label.set_label(lab);
	}

	void XY_axis::set_y_label(const string& lab)
	{
		y.label.set_label(lab);
	}

	
};

20.1 阶乘的迭代实现和递归实现

递归版本代码简单粗暴,但是我选迭代,因为递归时的函数调用花费时间较长,且会占用内存空间,存在耗尽内存资源的风险,而迭代速度快占用空间小,首选。

//阶乘

//迭代版本
int fac_iter(int n)
{
	int sum{ 1 };
	while (n > 1)
	{
		sum *= n;
		--n;
	}
	return sum;
}

//递归版本
int fac_recur(int n)
{
	return n > 1 ? n * fac_recur(n - 1) : 1;
}

20.2 and 20.3 Func类——可灵活改变的Function类派生类

加了模板参数,另外

template<class PrecType = double>
	class Func : public Function {
		Fct fct;
		double r1, r2;
		Point cen;
		int cnt;
		double xs, ys;
		PrecType prec;
	protected:
		void reset();

	public:
		Func(Fct f, double r1, double r2, Point orig, 
			int count = 100, double xscale = 25, double yscale = 25, 
			PrecType prec = PrecType(1));

		void reset_function(Fct f);
		void reset_range(double r1, double r2);
	};

	//------------------------------------------------------------------
	template<class PrecType>
	Func<PrecType>::Func(Fct f, double r1, double r2, Point orig,
		int count, double xscale, double yscale, PrecType precision)
		: Function(f, r1, r2, orig, count, xscale, yscale),
		fct{ f }, r1{ r1 }, r2{ r2 }, cen{ orig },
		cnt{ count }, xs{ xscale }, ys{ yscale }, prec{ precision}
	{	}

	template<class PrecType>
	void Func<PrecType>::reset()
	{
		PrecType dist = PrecType(r2 - r1) / cnt;
		PrecType r = r1;
		int np = number_of_points();
		int i;
		for (i = 0; i < np; ++i)
		{
			Point p{ cen.x + int(r * xs), cen.y - int(PrecType(fct(r)) * ys) };
			set_point(i, p);
			r += dist;
		}
		for (i = np; i < cnt; ++i)
		{
			add(Point{ cen.x + int(r * xs), cen.y - int(PrecType(fct(r)) * ys) });
			r += dist;
		}
	}

	template<class PrecType>
	void Func<PrecType>::reset_function(Fct f)
	{
		fct = f;
		reset();
	}

	template<class PrecType>
	void Func<PrecType>::reset_range(double rg1, double rg2)
	{
		if (rg2 - rg1 <= 0)
			error("bad graphing range");
		r1 = rg1;
		r2 = rg2;
		reset();
	}

20.4 Trigonometric Function

#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Simple_window.h"
#include"../../GUI/Graph.h"


//注意,Graph.h中的 Fct 类型:typedef std::function<double(double)> Fct;
//这个类型是强制类型安全的,而 sin cos 这些三角函数在<cmath>中有两个类型重载,
//这两个重载分别返回和接收float,long double类型,所以会出问题
//考虑用 lambda 并且显示指定返回值

//如果你的Graph.h中的Fct类型定义是 typedef double Fct(double);
// 那就不用多此一举了,直接用 sin cos这样的即可



int main()
try
{
	constexpr int xmax = 1200;	//窗口大小
	constexpr int ymax = 900;
	Point tt{ 200,100 };
	Simple_window win{ tt, xmax, ymax, "20-4 Trigonometric Function graphs" };

	//绘制坐标轴
	constexpr double scale{ 50 };
	constexpr int xorig{ xmax/2 };	//坐标原点位于窗口中的相对位置
	constexpr int yorig{ ymax/2 };
	const Point orign{ xorig,yorig };//坐标原点
	
	constexpr int axis_xlen{ xmax - 100 };	//坐标轴长度
	constexpr int axis_ylen{ ymax - 100 };

	const string xlabel{ "x" };
	const string ylabel{ "y" };
	Axis x{ Axis::x, Point{xorig - axis_xlen / 2, yorig},axis_xlen,
			int(axis_xlen / scale), xlabel };
	//x.label.move(-100, 0);
	Axis y{ Axis::y, Point{xorig, yorig + axis_ylen / 2}, axis_ylen,
			int(axis_ylen / scale), ylabel };
	x.set_color(Color::red);
	y.set_color(Color::red);
	win.attach(x);
	win.attach(y);

	//绘制函数
	constexpr double r_min{ -10 };		//区间为[-10:11)
	constexpr double r_max{ 11 };
	constexpr int np{ 400 };	//在区间中用到的点的数量
	constexpr double xscale{ scale };
	constexpr double yscale{ scale };
	
	Function f1{ [](double x)->double {return sin(x); },
		r_min,r_max,orign,np,xscale,yscale };
	f1.set_color(Color::red);
	
	Function f2{ [](double x)->double {return cos(x); },
		r_min,r_max,orign,np,xscale,yscale };
	f2.set_color(Color::yellow);
	
	Function f3{ [](double x)->double {return sin(x) + cos(x); },
		r_min,r_max,orign,np,xscale,yscale };
	f3.set_color(Color::blue);

	Function f4{ [](double x)->double {return sin(x)*sin(x) + cos(x)*cos(x); },
		r_min,r_max,orign,np,xscale,yscale };
	f4.set_color(Color::green);

	win.attach(f1);
	win.attach(f2);
	win.attach(f3);
	win.attach(f4);

	win.wait_for_button();

	return 0;
}
catch (runtime_error& e)
{
	cerr << "Runtime error: " << e.what() << '\n';
	return 1;
}
catch (...)
{
	cerr << "Exception occurred!\n";
	return 2;
}

19.5 Leibniz Series

#include"../../GUI/std_lib_facilities.h"
#include"../../GUI/Simple_window.h"
#include"../../GUI/Graph.h"

template<class VType = double>
class Scale {
	int cbase;
	VType vbase;
	double scale;
public:
	Scale(int b, VType v, double s)
		:cbase{ b }, vbase{ v }, scale{ s }{}
	int operator()(VType v) const
	{
		return cbase + round((v - vbase) * scale);
	}
};

double term_Lebiniz(int n)
{
	return (n % 2 ? 1.0 : -1.0) / (2.0 * n - 1.0);
}


int main()
try
{
	constexpr int xmax = 1200;	//窗口大小
	constexpr int ymax = 900;
	Point tt{ 200,100 };
	Simple_window win{ tt, xmax, ymax, "20-5 Leibniz Series" };

	//绘制坐标轴
	constexpr double PI = 3.1415926;
	constexpr int axis_xlen{ xmax - 100 };	//坐标轴长度
	constexpr int xorig{ (xmax - axis_xlen) / 2 };	//坐标原点位于窗口中的相对位置
	constexpr int yorig{ ymax / 4 };
	
	constexpr double base_rad{ 0 };		//数据范围,弧度
	constexpr double end_rad{ PI / 2 };
	constexpr double scale{ axis_xlen / (end_rad - base_rad) };
	Scale<double> xs(xorig, base_rad, scale);

	const string xlabel{ "x" };
	Axis x{ Axis::x, Point{xorig, yorig},axis_xlen,	2, xlabel };
	x.set_color(Color::red);
	x.label.move(-axis_xlen, 0);
	win.attach(x);
	Text t1{ Point{xs(PI / 4)-10, yorig + 15},"PI/4" };
	Text t2{ Point{xs(PI / 2)-10, yorig + 15},"PI/2" };
	t1.set_color(Color::black);
	t2.set_color(Color::black);
	win.attach(t1);
	win.attach(t2);
	
	Line quarterPI{ Point{xs(PI / 4),yorig}, Point{xs(PI / 4),100} };
	quarterPI.set_color(Color::blue);
	win.attach(quarterPI);

	//采用了和书上不太一样的计算级数的方法,节约点计算资源
	double sum{ 0.0 };
	for (int n = 1; n < 20; ++n)
	{
		ostringstream oss;
		oss << "Leibniz Series approximation; n == " << n;
		win.set_label(oss.str());
		sum += term_Lebiniz(n);
		Mark m{ Point{xs(sum),yorig},'x' };
		m.set_color(Color::black);
		win.attach(m);
		win.wait_for_button();
		win.detach(m);
	}

	win.wait_for_button();
	return 0;
}
catch (runtime_error& e)
{
	cerr << "Runtime error: " << e.what() << '\n';
	return 1;
}
catch (...)
{
	cerr << "Exception occurred!\n";
	return 2;
}

19.6 and 19.7 Histogram 柱状图

实现

//辅助计算位置的类
template<class VType = double>
class Scale {
	int cbase;
	VType vbase;
	double scale;
public:
	Scale(int b, VType v, double s)
		:cbase{ b }, vbase{ v }, scale{ s }{}
	int operator()(VType v) const
	{
		return cbase + round((v - vbase) * scale);
	}
};

//下面是完整实现
class XY_axis : public Shape {
	//一个XY坐标轴
	Axis x;
	Axis y;
	Point o;	//原点
	int xlen;	//x轴长度
	int ylen;
public:
	XY_axis(Point oo, int xlength, int ylength, 
		const string & xlab = "x", const string & ylab = "y");
	void draw_lines() const override;
	void move(int dx, int dy) override;
	void set_color(Color c);
	void set_x_label(const string& lab);
	void set_y_label(const string& lab);
};

XY_axis::XY_axis(Point oo, int xlength, int ylength,
	const string& xlab, const string& ylab)
	:x{Axis::x, oo, xlength, 0, xlab},
	 y{ Axis::y, oo, ylength, 0, ylab },
	 o{oo}, xlen{xlength},ylen{ylength}
{
	if (xlen <= 0 || ylen <= 0)
		error("Bad XY Axis: non-positive length of X or Y axis");
}

void XY_axis::draw_lines() const
{
	x.draw();
	y.draw();
}

void XY_axis::move(int dx, int dy)
{
	x.move(dx, dy);
	y.move(dx, dy);
}

void XY_axis::set_color(Color c)
{
	Shape::set_color(c);
	x.set_color(c);
	y.set_color(c);
}

void XY_axis::set_x_label(const string& lab)
{
	x.label.set_label(lab);
}

void XY_axis::set_y_label(const string& lab)
{
	y.label.set_label(lab);
}

//----------------------------------------------------------------------------
template<typename DataType>
class Bar : public Graph_lib::Rectangle {
	//带标签的柱状图
public:
	Bar(Point cen, int width, int height, pair<string, DataType> psd);
	void draw_lines() const override;
	void move(int dx, int dy) override;
	void set_color(Color c);
	
	Text label;	//柱体下面的标签
	Text data;	//柱体上面的数字标识
};

template<typename DataType>
Bar<DataType>::Bar(Point cen, int width, int ytop, pair<string,DataType> psd)
	:Rectangle{ Point{cen.x - int(round(width / 2.0)), ytop},
				Point{cen.x + int(round(width / 2.0)), cen.y} },
	label{ Point{cen.x - int(round(width / 2.0)),cen.y + 15}, psd.first },
	data{ Point{cen.x - int(round(width / 2.0)),ytop - 1}, ""}
{
	ostringstream oss;
	oss << psd.second;
	data.set_label(oss.str());
}

template<typename DataType>
void Bar<DataType>::draw_lines() const
{
	Rectangle::draw_lines();
	label.draw();
	data.draw();
}

template<typename DataType>
void Bar< DataType>::move(int dx, int dy)
{
	Rectangle::move(dx, dy);
	label.move(dx, dy);
	data.move(dx, dy);
}

template<typename DataType>
void Bar<DataType>::set_color(Color c)
{
	Rectangle::set_color(c);
	label.set_color(c);
	data.set_color(c);
}

//---------------------------------------------------------------------

template<typename DataType>
//DataType 必须是数字类型
class Histogram : public Shape {
	vector<pair<string,DataType>> datas;	//(标签,数据)对
	XY_axis xy_axis;		//一个坐标系
	Text title;
	Vector_ref<Bar<DataType>> bars;	//带标签柱形状集

public:
	Histogram(Point xy, int width, int height,
		const vector<pair<string,DataType>>vdata, const string& title = "");

	void draw_lines() const override;
	void move(int dx, int dy) override;
	
	void set_color_all(Color c);
	void set_fill_color_bars_all(Color c);

	void set_bar_color_by_index(int index, Color c);
	void set_bar_fill_color_by_index(int index, Color c);

	void set_title(const string& tt);
	void set_xaxis_label(const string& xstr);
	void set_yaxis_label(const string& ystr);
	void set_bar_label_by_index(int index, const string& str);
	//...
};

//---------------------------------------------------------------------
template<typename DataType>
Histogram<DataType>::Histogram(Point xy, int width, int height,
	const vector<pair<string,DataType>> vdata, const string& tt)
	: datas{ vdata },
	xy_axis{ Point{ xy.x, xy.y + height - 15 }, width, height - 30 },
	title{ Point{xy.x + width / 2, xy.y + 14}, tt }
{
	if (datas.size() == 0)
		return;
	//这里有一个隐含条件,期望datas都是大于零的数
	DataType max{ datas[0].second };
	for (auto pd : datas)
		if (pd.second > max)
			max = pd.second;
	const int space_for_text{ 15 };
	const int axis_ylen = height - 2 * space_for_text;
	const int yorig = xy.y + height - space_for_text;
	const double xscale{ double(width) / (datas.size() + 1) };
	const double yscale{ double(axis_ylen - space_for_text) / max };
	Scale<DataType> xs{ xy.x, 0, xscale };
	Scale<DataType> ys{ yorig, 0, -yscale };

	//计算柱宽,而且每条柱间隔一个柱宽
	const int bar_width = round(double(width) / (2 * datas.size()));
	for (int i = 0; i < datas.size(); ++i)
	{
		bars.push_back(new Bar<DataType>{ Point{xs(i + 1),yorig},bar_width,ys(datas[i].second),datas[i] });
		bars[bars.size() - 1].set_color(Color::black);
		bars[bars.size() - 1].set_fill_color(Color::white);
	}
	xy_axis.set_color(Color::red);
	title.set_color(Color::black);
}

template<typename DataType>
void Histogram<DataType>::draw_lines() const
{
	xy_axis.draw();
	title.draw();
	for (int i = 0; i < bars.size(); ++i)
		bars[i].draw();
}

template<typename DataType>
void Histogram<DataType>::move(int dx, int dy)
{
	xy_axis.move(dx, dy);
	title.move(dx, dy);
	for (int i = 0; i < bars.size(); ++i)
		bars[i].move(dx, dy);
}

template<typename DataType>
void Histogram<DataType>::set_color_all(Color c)
{
	xy_axis.set_color(c);
	title.set_color(c);
	for (int i = 0; i < bars.size(); ++i)
		bars[i].set_color(c);
}

template<typename DataType>
void Histogram<DataType>::set_fill_color_bars_all(Color c)
{
	for (int i = 0; i < bars.size(); ++i)
		bars[i].set_fill_color(c);
}

template<typename DataType>
void Histogram<DataType>::set_bar_color_by_index(int index, Color c)
{
	if (index >= bars.size())
		error("Bad index: out of range");
	bars[index].set_color(c);
}

template<typename DataType>
void Histogram<DataType>::set_bar_fill_color_by_index(int index, Color c)
{
	if (index >= bars.size())
		error("Bad index: out of range");
	bars[index].set_fill_color(c);
}

template<typename DataType>
void Histogram<DataType>::set_title(const string& tt)
{
	title.set_label(tt);
}

template<typename DataType>
void Histogram<DataType>::set_xaxis_label(const string& xlab)
{
	xy_axis.set_x_label(xlab);
}

template<typename DataType>
void Histogram<DataType>::set_yaxis_label(const string& ylab)
{
	xy_axis.set_y_label(ylab);
}

template<typename DataType>
void Histogram<DataType>::set_bar_label_by_index(int index, const string& lab)
{
	if (index >= bars.size())
		error("Bad index: out of range");
	bars[index].label.set_label(lab);
}

测试

#include"Func_Data_Graph.h"

using namespace Func_Data_Graph;

int main()
try
{
	constexpr int xmax = 1200;	//窗口大小
	constexpr int ymax = 900;
	Point tt{ 200,100 };
	Simple_window win{ tt, xmax, ymax, "Histogram" };

	string str{ "" };
	vector<pair<string,double>> data;
	data.push_back({str,15.2});
	data.push_back({ "",73.65 });
	data.push_back({ "c",197.56 });
	data.push_back({ "d",135.72 });
	Histogram<double> hg{ Point{200,100}, 600, 600, data, "title_1"};
	win.attach(hg);
	win.wait_for_button();

	hg.set_fill_color_bars_all(Color::yellow);
	win.wait_for_button();

	hg.set_color_all(Color::green);
	win.wait_for_button();

	hg.set_xaxis_label("xxx");
	hg.set_yaxis_label("yyy");
	win.wait_for_button();

	hg.set_title("title_2");
	win.wait_for_button();

	hg.set_bar_label_by_index(0, "red");
	hg.set_bar_fill_color_by_index(0, Color::red);
	win.wait_for_button();

	hg.set_bar_color_by_index(2, Color::blue);
	win.wait_for_button();

	return 0;
}
catch (runtime_error& e)
{
	cerr << "Runtime error: " << e.what() << '\n';
	return 1;
}
catch (...)
{
	cerr << "Exception occurred!\n";
	return 2;
}

20.8 Height Distribution Histogram

使用了柱状图

#include"Func_Data_Graph.h"

using namespace Func_Data_Graph;


istream& operator>>(istream& is, pair<string, int>& p)
{
	char ch1{ 0 }, ch2{ 0 }, ch3{ 0 };
	int h{ 0 }, f{ 0 };	//身高和数量

	is >> ch1;
	if (ch1 != '(')
	{
		is.unget();
		is.clear(ios::failbit);
		return is;
	}
	if (is >> h >> ch2 >> f >> ch3)
	{
		if (ch2 != ',' || ch3 != ')')
			is.clear(ios_base::failbit);
		else
		{
			ostringstream oss;
			oss << h;
			p.first = oss.str();
			p.second = f;
		}
	}
	return is;
}

void read_data(const string& fname, vector<pair<string, int>>& vd)
{
	ifstream ifs{ fname };
	if (!ifs)
		error("can't open ", fname);
	while (true)
	{
		pair<string, int> phd;	//身高分布对
		if (!(ifs >> phd)) break;
		vd.push_back(phd);
	}
}

int main()
try
{
	constexpr int xmax = 1200;	//窗口大小
	constexpr int ymax = 900;
	Point tt{ 200,100 };
	Simple_window win{ tt, xmax, ymax, "" };

	string fname{ "heights.txt" };
	vector<pair<string, int>> vd;
	read_data(fname, vd);

	Histogram<int> hg{ Point{200,100}, 800, 600, vd, "Height Distribution" };
	win.attach(hg);
	win.wait_for_button();

	return 0;
}
catch (runtime_error& e)
{
	cerr << "Runtime error: " << e.what() << '\n';
	return 1;
}
catch (...)
{
	cerr << "Exception occurred!\n";
	return 2;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为编写实际的应用程序做好准备:无论你是为了进行软件开发还是进行其他领域的工作。《C++程序设计原理实践(英文版)》假定你的最终目标是学会编写实际有用的程序。以基本概念和基本技术为重点:与传统的C++教材相比,《C++程序设计原理实践(英文版)》对基本概念和基本技术的介绍更为深入。这会为你编写有用、正确.易维护和有效的代码打下坚实的基础。, 用现代C++语言编程:, 《C++程序设计原理实践(英文版)》一方面介绍了通用的程序设计方法(包括面向对象程序设计和泛型程序设计)。另一方面还对软件开发实践中使用最广泛的程序设计语言——C++进行了很好的介绍。《C++程序设计原理实践(英文版)》从开篇就开始介绍现代C++程序设计技术,并介绍了大量关于如何使用C++标准库来简化程序设计的内容。, 适用于初学者以及任何希望学习新知识的人:, 《C++程序设计原理实践(英文版)》主要是为那些从未编写过程序的人编写的。而且已经由超过1000名大学一年级新生试用过。不过,对于专业人员和高年级学生来说,通过观察公认的程序设计大师如何处理编程中的各种问题。同样也会获得新的领悟和指引。, 提供广阔的视野:, 《C++程序设计原理实践(英文版)》第一部分非常广泛地介绍了基本程序设计技术,包括基本概念、设计和编程技术、语言特性以及标准库。这些内容教你如何编写具有输入、输出、计算以及简单图形显示等功能的程序。《C++程序设计原理实践(英文版)》第二部分则介绍了一些更专门性的内容(如文本处理和测试),并提供了大量的参考资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值