C++沉思录 第八章 面向对象程序范例

c++沉思录第八章的示例程序很有意思。程序虽小,却很好地诠释了面向对象编程的思想
正如书上说的仔细研究还是有所收获的。

先上代码

code

Expr_node.h

#pragma once
#include "Expr.h"
#include<string>

using namespace std;

//Expr_node 基类
class Expr_node {
    friend class Expr;
    int use;
public:
    Expr_node() :use(1){}
    virtual ~Expr_node(){}
    virtual void print(std::ostream&) const = 0;
};

class Int_node :public Expr_node{
    int n;
    void print(ostream& o) const { o << n; }
public:
    Int_node(int k):n(k){}
};

class Unary_node :public Expr_node{
    //friend class Expr;
    string op;
    Expr opnd;
    void print(ostream& o) const
    {
        o << "(" << op << opnd << ")";
    }
public:
    Unary_node(const string& a, Expr b) :op(a), opnd(b){}
};
class Binary_node :public Expr_node{
    //friend class Expr;
    string op;
    Expr left;
    Expr right;
    void print(ostream& o) const
    {
        o << "(" << left << op << right << ")";
    }
public:
    Binary_node(const string& a, Expr b, Expr c) :op(a), left(b), right(c){}
};

Expr_node.cpp


#include "stdafx.h"
#include "Expr_node.h"

句柄类Expr

Expr.h

#pragma once
#include<iostream>

using namespace std;
class Expr_node;
class Expr{
    friend ostream& operator<<(ostream&, const Expr&);
    Expr_node* p;
public:
    Expr();
    Expr(int);
    Expr(const string&, Expr&);
    Expr(const string&, Expr&, Expr&);

    Expr(const Expr& t);
    Expr& operator=(const Expr&);
    ~Expr();
};

Expr.cpp

#include "stdafx.h"
#include "Expr.h"
#include "Expr_node.h"

Expr::Expr()
{
}

Expr::~Expr()
{
    if (--p->use == 0)
        delete p; 
}
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);
}
Expr::Expr(const Expr& t)
{
    p = t.p; ++p->use;
}

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;
}

测试程序:

Ooptest.cpp

#include "stdafx.h"
#include<iostream>
#include<string>
#include "Expr.h"

int main(int argc, char* argv[])
{
    //Expr a = Expr("-", Expr(5));
    //Expr b = Expr("+", Expr(3),Expr(4));
    Expr t = Expr("*", Expr("-", Expr(5)), Expr("+", Expr(3), Expr(4)));
    std::cout << t << std::endl;
    return 0;
}

分析:

这里总共3个类。

Expr
这个称之为句柄类。其实可以理解为马甲~~-.-

其作用是帮助管理了内存分配,引用计数等问题。

Expr_node

3种表达式的基类。
抽象出print等函数,因为具体的打印应该由具体的表达式来输出。
提供use成员变量来计数。其实这个变量是为了给Expr用的。

当2个Expr_node对象相互赋值时,由Expr这个句柄类来管理计数值,比如a=b,b引用的对象应该+1,因为现在a也来引用了。而a原来引用的应该-1,因为a找到了新的对象。。。当某个对象引用计数为0时,Expr就delete掉这个对象,这个所有的过程都是Expr完成的。

其实这里还有几个语法点
这里的程序和书上的略有不同。
比如:


class Unary_node :public Expr_node{
    //friend class Expr;
    string op;
    Expr opnd;
    void print(ostream& o) const
    {
        o << "(" << op << opnd << ")";
    }
public:
    Unary_node(const string& a, Expr b) :op(a), opnd(b){}
};

书上用到了friend,友元的概念。

这里的意思是把Expr声明为Unary_node的友元类,那么会有什么变化呢?

这个效果就是Expr可以访问Unary_node的的隐藏信息包括 私有成员和保护成员了。

然后Expr.cpp里的这行代码就合法了。因为创建对象要调用构造函数,而这个构造函数是private的。

p = new Unary_node(op, t);

我这里加上public,就可以注释掉那一行了。

再看下Expr.h

class Expr_node;
class Expr{
    friend ostream& operator<<(ostream&, const Expr&);
    Expr_node* p;

这里只是声明了下 Expr_node,因为下面只是用到了Expr_node*
而没有

#include "Expr_node.h"

这里又涉及到了头文件包含的技巧,以及编译器如何来编译的问题。

这样可以避免头文件包含来包含去的,免得又是一堆编译报错。

不过后面在Expr.cpp。还是需要include进来。

end

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值