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

目次へ戻る

11.1

問題の意図がよくわからない。
#include <iostream>
using namespace std;

struct X {
    int i;
    X(int){cout << " X::X(int)\n";}
    X operator+(int){cout << " X::oper+(int)\n"; return *this;}
};

struct Y {
    int i;
    Y(X){cout << " Y::Y(X)\n";}
    Y operator+(X){cout << " Y::oper+(X)\n"; return *this;}
    operator int(){cout << " Y::oper int()\n"; return 0;}
};

X operator*(X x,Y){cout << " oper*(X,Y)\n"; return x;}
int f(X){cout << " f(X)\n"; return 0;}

X x = 1;
Y y = x;
int i = 2;

int main()
{
    cout << "i+10\n"; i+10;
    cout << "y+10\n"; y+X(10);
    cout << "y+10*y\n"; y+X(10*static_cast<int>(y));
    cout << "x+y+i\n"; x+y+i;
    cout << "x*x+i\n"; x*x+i;
    cout << "f(7)\n"; f(7);
    cout << "f(y)\n"; f(X(y));
    cout << "y+y\n"; y+y;
    cout << "106+y\n"; 106+y;
}

11.2

パス。

11.3

class INT {
    int i;
public:
    INT(int i0 = 0) : i(i0) {}
    operator int(){return i;}
    int operator+=(int i0){return i+=i0;}
    // -= 等は省略
};
struct X {X(int){}};

void f(int i){}
void g(int& i){}
void h(X x){}

int main()
{
    int     i;
    INT     j, k = 2;
    j += 4 * k;
    f(i);
    f(j);
    g(i);
    g(j);   // エラー
    h(i);
    h(j);   // エラー
}
「int と全く同じように動作する」とは、どこまで言うのだろう?

11.4

まさしく四則演算しか定義しなかったので、無理矢理結果を見ている。
#include <iostream>
using namespace std;

class RINT {
    friend int operator+(const RINT& r,const RINT& s);
    friend int operator-(const RINT& r,const RINT& s);
    friend int operator*(const RINT& r,const RINT& s);
    friend int operator/(const RINT& r,const RINT& s);
    friend int operator%(const RINT& r,const RINT& s);
    int i;
public:
    RINT(int i0 = 0) : i(i0) {}
    int operator+(){return i;}
    int operator-(){return -i;}
};
int operator+(const RINT& r,const RINT& s){return r.i+s.i;}
int operator-(const RINT& r,const RINT& s){return r.i-s.i;}
int operator*(const RINT& r,const RINT& s){return r.i*s.i;}
int operator/(const RINT& r,const RINT& s){return r.i/s.i;}
int operator%(const RINT& r,const RINT& s){return r.i%s.i;}

int main()
{
    RINT    j, k = 2;
    j = 1 + 4 * -k;
    cout << *reinterpret_cast<int*>(&j) << endl;
}

11.5

前問で int を __int64 にする。(VC の場合)

11.6

正確に言えば任意の精度ではない。(size_t の桁数しかだめ) また、効率は重視していないし、問題もあるかもしれない。 vector でなく valarray でもよかったかも。
#include <cassert>
#include <vector>
#include <iostream>
using namespace std;

class CInt {
    typedef vector<char> VType;
    VType       m_data;     // 1要素1桁
    bool        m_sign;     // 符号が正
    int GetAt(int n)const{return n < m_data.size() ? m_data[n] : 0;}
    void SetAt(int n,int i)
        {if (n >= m_data.size()) m_data.resize(n+1); m_data[n] = i;}
    void Trim(){while (m_data.size() > 0 && m_data.back() == 0)
        m_data.pop_back();}
    void Reset(int i);
    void Add(const CInt& i,int pos = 0,int r = 1);
    void Sub(const CInt& i);
public:
    CInt(int i = 0){Reset(i);}
    ostream& Print(ostream& o)const;
    CInt operator-()const
        {CInt i = *this; i.m_sign = !i.m_sign; return i;}
    CInt& operator++(){*this += 1; return *this;}
    CInt& operator--(){*this -= 1; return *this;}
    CInt operator++(int){CInt i = *this; *this += 1; return i;}
    CInt operator--(int){CInt i = *this; *this -= 1; return i;}
    CInt operator+(const CInt& i)const;
    CInt operator-(const CInt& i)const;
    CInt operator*(const CInt& i)const;
    CInt operator/(const CInt& i)const;
    CInt& operator+=(const CInt& i){return *this = *this + i;}
    CInt& operator-=(const CInt& i){return *this = *this - i;}
    CInt& operator*=(const CInt& i){return *this = *this * i;}
    CInt& operator/=(const CInt& i){return *this = *this / i;}
    CInt& operator*=(int i);
    bool operator==(const CInt& i)const;
    bool operator<(const CInt& i)const;
    bool operator>(const CInt& i)const{return i < *this;}
    bool operator<=(const CInt& i)const{return !(i < *this);}
    bool operator>=(const CInt& i)const{return !(*this < i);}
};

void CInt::Reset(int i)
{
    if (!(m_sign = i >= 0)) i = -i;
    m_data.clear();
    while (i) {
        m_data.push_back(i%10);
        i /= 10;
    }
}
void CInt::Add(const CInt& i,int pos,int r)
{
    int     j, n = 0, m = i.m_data.size();
    for (j=0;j<m;++j) {
        n += GetAt(j+pos) + i.m_data[j] * r;
        SetAt(j+pos,n%10);
        n /= 10;
    }
    j += pos;
    while (n) {
        n += GetAt(j);
        SetAt(j++,n%10);
        n /= 10;
    }
}
void CInt::Sub(const CInt& i)
{
    int     j,k, n = 0, l = m_data.size(), m = i.m_data.size();
    assert(l >= m);
    for (j=0;j<m;++j) {
        k = n + m_data[j] - i.m_data[j];
        n = 0;
        while (k < 0) {k += 10; --n;}
        m_data[j] = k;
    }
    while (n && j < l) {
        k = n + m_data[j];
        n = 0;
        while (k < 0) {k += 10; --n;}
        m_data[j++] = k;
    }
    assert(n == 0);
    Trim();
}
ostream& CInt::Print(ostream& o)const
{
    VType::const_reverse_iterator it;
    if (!m_data.size())
        return o << '0';
    if (!m_sign) o << '-';
    for (it=m_data.rbegin();it!=m_data.rend();++it)
        o << static_cast<int>(*it);
    return o;
}
CInt CInt::operator+(const CInt& i)const
{
    if (m_sign != i.m_sign)
        return m_sign ? *this - -i : i - -*this;
    if (*this < i) return i + *this;
    CInt    j = *this;
    j.Add(i);
    return j;
}
CInt CInt::operator-(const CInt& i)const
{
    if (!m_sign && !i.m_sign) return -i - -*this;
    else if (!m_sign)         return -(-*this + i);
    else if (!i.m_sign)       return *this + -i;
    else if (*this < i)       return -(i - *this);
    CInt    j = *this;
    j.Sub(i);
    return j;
}
CInt CInt::operator*(const CInt& i)const
{
    CInt    r;
    int     j, m = i.m_data.size();
    for (j=0;j<m;++j)
        r.Add(*this,j,i.m_data[j]);
    r.m_sign = m_sign == i.m_sign;
    return r;
}
CInt CInt::operator/(const CInt& i)const
{
    CInt    r,d;
    int     j,k, m = m_data.size();
    for (j=m-1;j>=0;--j) {
        d.m_data.insert(d.m_data.begin(),m_data[j]);
        k = 0;
        while (d >= i) {d.Sub(i); ++k;}
        r.m_data.insert(r.m_data.begin(),k);
    }
    r.Trim();
    r.m_sign = m_sign == i.m_sign;
    return r;
}
CInt& CInt::operator*=(int i)
{
    if (i < 0) {i = -i; m_sign = !m_sign;}
    int     j, n = 0, m = m_data.size();
    for (j=0;j<m;++j) {
        n += m_data[j] * i;
        m_data[j] = n%10;
        n /= 10;
    }
    while (n) {
        SetAt(j++,n%10);
        n /= 10;
    }
    return *this;
}
bool CInt::operator==(const CInt& i)const
{
    int     j, m = m_data.size();
    if (m_sign != i.m_sign || m != i.m_data.size())
        return false;
    for (j=0;j<m;++j)
        if (m_data[j] != i.m_data[j]) return false;
    return true;
}
bool CInt::operator<(const CInt& i)const
{
    if (!m_sign && !i.m_sign) return -i < -*this;
    else if (!m_sign)         return true;
    else if (!i.m_sign)       return false;
    int     j,k, m = m_data.size(), m2 = i.m_data.size();
    if (m < m2)               return true;
    else if (m > m2)          return false;
    for (j=m-1;j>=0;--j)
        if ((k = m_data[j] - i.m_data[j])) return k < 0;
    return false;
}
ostream& operator<<(ostream& o,const CInt& i){return i.Print(o);}

int main(int argc,char** argv)
{
    CInt    i = 1, ii = 1;
    int     j,n = argc > 1 ? atoi(argv[1]) : 1000;
    for (j=2;j<=n;++j) i *= j;
    cout << i << endl;
    for (j=2;j<=n;++j) ii *= CInt(j);
    cout << i-ii << endl;
}

11.7

String を作らなかったのでパス。

11.8

String を作らなかったのでパス。

11.9

String を作らなかったのでパス。

11.10

String を作らなかったのでパス。

11.11

パス。

11.12

パス。

11.13

#include <iostream>
using namespace std;

class INT {
    int i;
public:
    INT(int i0 = 0) : i(i0) {}
    int operator*(int i0){return i*(i0+2);}
    operator int(){return i;}
};
#define int INT

int main()
{
    // + と * の優先順位を逆にしてみた
    int     i = 2, j = 3, k = 4;
    if (i*j+k == 2*(3+4)) cout << "ok 1\n";
    if (i+j*k == (2+3)*4) cout << "ok 2\n";
}

11.14

パス。

11.15

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

struct Vec4 : valarray<float> {
    Vec4(float f[]) : valarray<float>(f,4) {}
};

ostream& operator<<(ostream& o,const valarray<float>& v)
{
    return o << "(" << v[0] << "," << v[1] << ","
        << v[2] << "," << v[3] << ")";
}

int main()
{
    float   f1[] = {1,2,3,4}, f2[] = {2,1,4,3};
    Vec4    v1(f1), v2(f2);
    cout << v1+v2 << endl;
    v1 += v2;
    cout << v1 << endl;
}

11.16

パス。

11.17

パス。

11.18

パス。

11.19

#include <iostream>
using namespace std;

template <typename T>
class Ptr_to_T {
    T*  p;      // 現在
    T*  array;  // 先頭
    int size;   // サイズ
    void check(T* pp)
    {if (pp < array || pp >= array+size) throw out_of_range("");}
public:
    Ptr_to_T(T* p0,T* v,int s) : p(p0), array(v), size(s) {}
    Ptr_to_T(T* p0) : p(p0), array(p0), size(1) {}
    Ptr_to_T& operator++(){++p; return *this;}
    Ptr_to_T operator++(int){Ptr_to_T t = *this; ++*this; return t;}
    Ptr_to_T& operator--(){--p; return *this;}
    Ptr_to_T operator--(int){Ptr_to_T t = *this; --*this; return t;}
    bool operator==(const Ptr_to_T& t){return p == t.p;}
    T& operator*(){check(p); return *p;}
};

int main()
{
    int             a[10];
    Ptr_to_T<int>   p(&a[0],a,10);
    if (++p == &a[1]) cout << "ok 1\n";
    if (p-- == &a[1]) cout << "ok 2\n";
    try {--p;} catch (out_of_range) {cout << "not use!\n";}
    try {*p;} catch (out_of_range) {cout << "out\n";}
}

11.20

struct S {int x,y;};
struct T {char* p; char* q;};
struct C : S,T {};

int main()
{
    C c;
    c.x = 0;
    c.p = 0;
}

11.21

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

class Index {
    double  d;
    friend double mypow(double d,Index i);
public:
    class Proxy {
        friend Index;
        friend double operator*(double d,const Proxy& p);
        Index& i;
        Proxy(Index& i0) : i(i0) {}
    };
    Index(double d0 = 0) : d(d0) {}
    Proxy operator*(){return Proxy(*this);}
};

double mypow(double d,Index i){return pow(d,i.d);}
double operator*(double d,const Index::Proxy& p)
{return mypow(d,p.i);}

int main()
{
    Index   i = 3;
    cout << 2 ** i << endl;
}

11.22

パス。
前章目次次章