<<C++ 沉思錄>> 中文人民郵電出版 勘誤
這本中文版裏面有各種坑爹的小錯誤. 比方說變量名的大小寫, 同一個變量, 出現了大小寫不一致, 等等問題都有.
然後今天感覺遇到了個語法問題. 關於繼承權限的問題.
書中第八章的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本來就是爲了明確不發生繼承的區域. 這裏這堆虛函數是要發生繼承的.就是爲了佔坑了讓子類去實現.
這裏應該使用public, 而不是 protected.
由於可能在"挑戰權威" , 所以把問題拋出來, 希望有心人能一起討論.
下面是完整的代碼. 可供測試
/*
Programmer : EOF
Date : 2015.05.19
File : 8.4.cpp
E-mail : [email protected]
*/
#include <iostream>
#include <string>
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<<(ostream&, const Expr&);
Expr_node* p;
public:
Expr():p(NULL){}
Expr(int);
Expr(const string&, Expr);
Expr(const string&, Expr, Expr);
Expr(const Expr& t) { p = t.p; ++p->use; };
Expr& operator=(const Expr&);
~Expr() { if(--p->use == 0) delete p;}
int eval() const {return p->eval();}
};
ostream&
operator<<(ostream& o, const Expr_node& e)
{
e.print(o);
return o;
}
Expr&
Expr::operator=(const Expr& rhs)
{
rhs.p->use++;
if(--p->use == 0)
{
delete p;
}
p = rhs.p;
return *this;
}
ostream&
operator<<(ostream& o, const Expr& t)
{
t.p->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, 聲明瞭一個友元 class B, 而B內部又聲明瞭一個函數F是B的友元.那麼F能訪問class A的private數據嘛?
答案是不能(個人觀點, 因爲我翻了C++ primer, 也沒有着重講這個問題, 自己測試的demo)
我這裏就特意定義了兩個類, C1和C2. C2是C1的友元, 就說明C2能夠訪問C1的private 或者protected成員.
但是! 這不意味着C2的友元能夠訪問C1的private區域.
下面的demo驗證了我的觀點:
#include <iostream>
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;
}
意圖都在註釋裏面. 把註釋和沒有註釋的是對比.
把注釋放出來就是在c2_print裏面會發生報錯. 因爲這裏C2 是C1的友元, c2_print是C2的友元, 但是這不具有傳遞性.不代表c2_print就是C1的友元.