C++第3版 25章 練習問題解答

目次へ戻る

25.1

テンプレートの特別バージョンを作ればよい。
#include <iostream>
using namespace std;

class Io_obj {
public:
    virtual Io_obj* clone()const = 0;
    virtual ~Io_obj(){}
};

template <typename T> class Io : public T, public Io_obj {
public:
    virtual Io_obj* clone()const{return new Io(*this);}
    Io(istream&);
    static Io* new_io(istream& s){return new Io(s);}
};

class Io<int> : public Io_obj {
    int     m_i;
public:
    virtual Io_obj* clone()const{return new Io(*this);}
    Io(istream& s){s >> m_i;}
    static Io* new_io(istream& s){return new Io(s);}
    operator int()const{return m_i;}
};

int main()
{
    Io<int>*     p = Io<int>::new_io(cin);
    cout << *p << endl;
}

25.2

手を抜いて Handle を完全には定義していない。しかし、問題についての解答にはなっていると思う。 メンバ関数テンプレートを使えないコンパイラだったらどうするんだろう?
template <typename X>
class Handle {
    X*  rep;
public:
    Handle(X* p=0) : rep(p) {}
    X* operator->()const{return rep;}
    template <typename T>
        Handle& operator=(const Handle<T>& t)
    {rep = t.operator->(); return *this;}
};

struct Shape {};
struct Circle : Shape {};
int main()
{
    Handle<Shape>   p;
    Handle<Circle>  q;
    p = q;
//  q = p; // NG
}

25.3

パス。

25.4

パス。

25.5

#include <string>
#include <iostream>
using namespace std;

class Filter {
public:
	class Retry {
	public:
		virtual const char* message(){return 0;}
	};
	virtual void start(){}
	virtual int read() = 0;
	virtual void write(){}
	virtual void compute(){}
	virtual int result() = 0;
	virtual int retry(Retry& m){cerr << m.message() << '\n'; return 2;}
	virtual ~Filter(){}
};

int main_loop(Filter* p)
{
	for (;;) {
		try {
			p->start();
			while (p->read()) {
				p->compute();
				p->write();
			}
			return p->result();
		} catch (Filter::Retry& m) {
			if (int i = p->retry(m)) return i;
		} catch (...) {
			cerr << "Fatal filter error\n";
			return 1;
		}
	}
}

class MyFilter : public Filter {
	istream&	is;
	ostream&	os;
	bool		same;
	string		str;
public:
	int read() {
		string s; is >> s;
		same = s == str;
		str = s;
		return is.good();}
	void write(){if (!same) os << str << " ";}
	int result(){return 0;}
	MyFilter(istream& i,ostream& o) : is(i), os(o), same(false) {}
};

int main()
{
	MyFilter f(cin,cout);
	return main_loop(&f);
}
ちょっと手抜きかな。

25.6

MyFilter のみを示す。残りは、前節と同じ。
#include <map>
#include <vector>
#include <algorithm>
class MyFilter : public Filter {
	istream&		is;
	ostream&		os;
	map<string,int>	buf;

	static bool comp(map<string,int>::iterator i,
		map<string,int>::iterator j) {
		return j->second < i->second;
	}
public:
	int read() {
		string s; is >> s;
		if (!s.empty()) ++buf[s];
		return is.good();}
	int result() {
		vector<map<string,int>::iterator> v;
		map<string,int>::iterator it;
		v.reserve(buf.size());
		for (it=buf.begin();it!=buf.end();++it)
			v.push_back(it);
		sort(v.begin(),v.end(),&comp);
		int		i, n = v.size();
		cout << endl;
		for (i=0;i<n;++i)
			cout << "(" << v[i]->first << "," << v[i]->second << ")\n";
		return 0;}
	MyFilter(istream& i,ostream& o) : is(i), os(o) {}
};
iostream って使ってないから良く分からん。

25.7

template <typename T,int L,int U>
struct Range {
};
これでどうしろと?

25.8

template <typename T>
struct Range {
	Range(int l=0,int u=1){}
};
Range クラスは何をすればいいの?

25.9

#include <cstdio>
#include <cstring>

class StringCheck;
class String {
	friend StringCheck;
	enum {Size = 8};
	char	s[Size];
public:
	String(){*s = 0;}
	void Set(const char* p){strcpy(s,p);}
	const char* toString()const{return s;}
};

class StringCheck {
	String	s;
public:
	void Set(const char* p) {
		if (p) {
			strncpy(s.s,p,String::Size-1);
			s.s[String::Size-1] = 0;
		} else s.s[0] = 0;
	}
	const char* toString()const{return s.toString();}
};

int main()
{
	StringCheck	s;
	s.Set("1234567890");
	printf("%s\n",s.toString());
	return 0;
}
ううむ。よくわからない。
基本的には、独立しているならば分離した方が汎用的になって使いやすいと思う。 しかし、上の例の様に完全に依存していると、逆に分かりにくくなると思う。
(そもそも、上の例はあっているのか?)

25.10

class Io_int : public Io_obj {
	int		i;
public:
	Io_int* clone()const{return new Io_int(*this);}
	Io_int(istream& is){is >> i;}
	static Io_int* new_int(istream& is){return new Io_int(is);}
};

io_map["Io_int"] = &Io_int::new_int;
コンパイルしていない。

25.11

パス。

25.12

パス。

25.13

#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
using namespace std;

struct Stack {
    virtual ~Stack(){}
    virtual void push(const int& t) = 0;
    virtual void pop() = 0;
    virtual int& top() = 0;
    virtual int top()const = 0;
    virtual bool empty()const = 0;
    virtual int size()const = 0;
};
class StackVector : public Stack {
    vector<int>   m_cont;
    StackVector(){}
    void Copy(Stack* p){while (!p->empty())
        m_cont.insert(m_cont.begin(),p->top()),p->pop();}
public:
    static Stack* New(){return new StackVector();}
    StackVector(Stack* p){Copy(p); delete p;}
    virtual void push(const int& t){m_cont.push_back(t);}
    virtual void pop(){m_cont.pop_back();}
    virtual int& top(){return m_cont.back();}
    virtual int top()const{return m_cont.back();}
    virtual bool empty()const{return m_cont.empty();}
    virtual int size()const{return m_cont.size();}
};
class StackList : public Stack {
    list<int>     m_cont;
    StackList(){}
    void Copy(Stack* p){while (!p->empty())
        m_cont.push_front(p->top()),p->pop();}
public:
    static Stack* New(){return new StackList();}
    StackList(Stack* p){Copy(p); delete p;}
    virtual void push(const int& t){m_cont.push_back(t);}
    virtual void pop(){m_cont.pop_back();}
    virtual int& top(){return m_cont.back();}
    virtual int top()const{return m_cont.back();}
    virtual bool empty()const{return m_cont.empty();}
    virtual int size()const{return m_cont.size();}
};

int main()
{
    Stack*  p = StackVector::New();
    p->push(2); p->push(3); p->push(1);
    p = new StackList(p);
    cout << p->top() << endl; p->pop();
    cout << p->top() << endl; p->pop();
    cout << p->top() << endl; p->pop();
}
STL の stack は、実装を静的に指定できる。 動的に指定できるのは、デザインパターンの Factory モデルであろうか。 問題は、「実行時に取り替えられる」である。(それとも、問題の意図を誤解しているか。)

25.14

パス。

25.15

パス。

25.16

パス。

25.17

パス。

25.18

パス。

25.19

#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;

template <typename T,typename U>
class Compose {
    T   m_func1;
    U   m_func2;
public:
    Compose(T t,U u) : m_func1(t), m_func2(u) {}
    template <typename X>
        X operator()(X x){return m_func1(m_func2(x));}
};
template <typename T,typename U>
Compose<T,U> Composer(T t,U u){return Compose<T,U>(t,u);}
int main()
{
    double x[] = {1,100,10000};
    transform(x,x+3,x,Composer(log10,sqrt));
    cout << x[0] << " " << x[1] << " " << x[2] << endl;
}

前章目次