中国語人民郵便出版の誤り


<>中国語人民郵便出版の誤り訂正
この中国語版にはいろいろな穴のお父さんの小さな間違いがある.例えば変数名の大文字と小文字、同じ変数、大文字と小文字が一致しないなどの問題がある.
そして今日は文法の問題にぶつかったような気がします.権限の継承に関する質問です.
本の中の第8章のdemoの中で、class Exprについてnode.
protectedキーワードが使用されています.でもここExpr_Nodeはベースクラスで、継承に問題が発生します.
具体的なコードは以下の通りです.
class Expr_node
{
    friend ostream& operator << (ostream&, const Expr_node&);
    friend class Expr;

    int use;// @use is a counter to avoid copying objects.

    //protected:
    public:
        Expr_node(): use(1) { }
        virtual void print(ostream&) const = 0;
        virtual ~Expr_node() { }
        virtual int eval() const = 0;
};

ここでprotectedを使えばerror.
protectedは本来、継承が起こらない領域を明確にするためである.ここでこの虚関数の山は継承される.穴を占拠して子類に実現させるためだ.
ここではprotectedではなくpublicを使用するべきです.
「権威に挑戦する」かもしれないので、問題を投げ出して、心ある人が一緒に討論してほしい.
次は完全なコードです.テスト可能
/*
    Programmer  :   EOF
    Date        :   2015.05.19
    File        :   8.4.cpp
    E-mail      :   [email protected]

 */
#include 
#include 

using namespace std;


/*
   This @Expr_node is the base-class.
 */
class Expr_node
{
    friend ostream& operator << (ostream&, const Expr_node&);
    friend class Expr;

    int use;// @use is a counter to avoid copying objects.

    protected:
    //public:
        Expr_node(): use(1) { }
        virtual void print(ostream&) const = 0;
        virtual ~Expr_node() { }
        virtual int eval() const = 0;
};


class Expr
{
    friend ostream& operator<use; };

        Expr& operator=(const Expr&);

        ~Expr() { if(--p->use == 0) delete p;}

        int eval() const {return p->eval();}
};

ostream&
operator<use++;
    if(--p->use == 0)
    {
        delete p;
    }

    p = rhs.p;
    return *this;
}

ostream&
operator<print(o);
    return o;
}

class Int_node: public Expr_node
{
    friend class Expr;

    int n;

    Int_node(int k): n(k) { }
    void print(ostream& o) const { o << n;}
    int eval() const { return n;}
};

class Unary_node: public Expr_node
{
    friend class Expr;
    string op;
    Expr opnd;
    Unary_node(const string& a, Expr b):
        op(a), opnd(b) { }

    void print(ostream& o) const
    {
        o << "(" << op << opnd << ")";
    }

    int eval() const
    {
        if(op == "-")
        {
            return -opnd.eval();
        }

        throw "error, bad op" + op + "int UnaryNode";
    }
};

class Binary_node: public Expr_node
{
    friend class Expr;
    string op;

    Expr left;
    Expr right;

    Binary_node(const string& a, Expr b, Expr c):
        op(a), left(b), right(c) { }

    void print(ostream& o) const
    {
        o << "(" << left << op << right << ")";
    }

    int eval() const
    {
        int op1 = left.eval();
        int op2 = right.eval();

        if(op == "-") return op1 - op2;
        if(op == "+") return op1 + op2;
        if(op == "*") return op1 * op2;
        if(op == "/") return op1 / op2;

        if(op == "/" && op2 != 0) return op1/ op2;

        throw "error, bad op" + op + "int BinaryNode";
    }
};

Expr::Expr(int n)
{
    p = new Int_node(n);
}

Expr::Expr(const string& op, Expr t)
{
    p = new Unary_node(op, t);
}

Expr::Expr(const string& op, Expr left, Expr right)
{
    p = new Binary_node(op, left, right);
}


int main()
{
    Expr t = Expr("*", Expr("-", 5), Expr("+", 3, 4));
    cout << t << " = " << t.eval() << endl;
    t = Expr("*", t, t);
    cout << t << " = " << t.eval() << endl;

    return 0;
}

「私の友元の友元は、必ずしも私の友元ではない」と証明するために
すなわち、現在のclass Aは、1つの友元class Bを宣言し、B内部はまた1つの関数FがBの友元であることを宣言する.ではFはclass Aのprivateデータにアクセスできますか?
答えはできません(個人的な観点では、C++primerをひっくり返したので、この問題を繰り返していません.自分でテストしたdemo)
C 1とC 2の2つのクラスを定義しましたC 2がC 1の友元であることは、C 2がC 1のprivateまたはprotectedメンバーにアクセスできることを示す.
でも!これはC 2の友元がC 1のprivate領域にアクセスできるという意味ではない.
次のdemoは私の観点を検証しました.
#include 

using namespace std;

class C1;
class C2;

class C1
{
    public:
        C1(const char* s): str_c1(s) { }
        friend void c1_print(class C1&);
        friend C2;

    private:
        const char* str_c1;
};

class C2
{
    public:
        C2(const char* s): str_c2(s){}

    private:
//        friend void c2_print(class C1&);
        const char* str_c2;
};

void c1_print(class C1 &tmp_c1)
{
    tmp_c1.str_c1 = "hello world";
}

void c2_print(class C1 &tmp_c1)
{
//    tmp_c1.str_c1 = "hello world";
}

int main()
{
    class C1 tmp_c1("I'm c1");
    class C2 tmp_c2("I'm c2");

    //c2_print(tmp_c1);
    c1_print(tmp_c1);
    return 0;
}

意図はすべて注釈の中にある.注釈と注釈がないのは
対比
コメントを出すのはc 2_printの中でエラーが発生します.ここC 2はC 1の友元なので、c 2_printはC 2の友元であるが、これは伝達性を持たない.c 2_を代表しないprintはC 1の友元です.