C++沉思录 第八章 面向对象程序范例
2015-08-05 16:51
459 查看
c++沉思录第八章的示例程序很有意思。程序虽小,却很好地诠释了面向对象编程的思想。
正如书上说的仔细研究还是有所收获的。
先上代码
Expr_node.cpp
句柄类Expr
Expr.h
Expr.cpp
测试程序:
Ooptest.cpp
Expr
这个称之为句柄类。其实可以理解为马甲~~-.-
其作用是帮助管理了内存分配,引用计数等问题。
Expr_node
3种表达式的基类。
抽象出print等函数,因为具体的打印应该由具体的表达式来输出。
提供use成员变量来计数。其实这个变量是为了给Expr用的。
当2个Expr_node对象相互赋值时,由Expr这个句柄类来管理计数值,比如a=b,b引用的对象应该+1,因为现在a也来引用了。而a原来引用的应该-1,因为a找到了新的对象。。。当某个对象引用计数为0时,Expr就delete掉这个对象,这个所有的过程都是Expr完成的。
其实这里还有几个语法点:
这里的程序和书上的略有不同。
比如:
书上用到了friend,友元的概念。
这里的意思是把Expr声明为Unary_node的友元类,那么会有什么变化呢?
这个效果就是Expr可以访问Unary_node的的隐藏信息包括 私有成员和保护成员了。
然后Expr.cpp里的这行代码就合法了。因为创建对象要调用构造函数,而这个构造函数是private的。
我这里加上public,就可以注释掉那一行了。
再看下Expr.h。
这里只是声明了下 Expr_node,因为下面只是用到了Expr_node*。
而没有
这里又涉及到了头文件包含的技巧,以及编译器如何来编译的问题。
这样可以避免头文件包含来包含去的,免得又是一堆编译报错。
不过后面在Expr.cpp。还是需要include进来。
正如书上说的仔细研究还是有所收获的。
先上代码
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
相关文章推荐
- system.cpp
- effetive C++ 02 尽量以const,enum,inline替换#define
- C++ primer plus 练习11
- C/C++在线笔试题总结(持续更新)
- c语言:括号匹配检测(栈的应用)
- TIOBE 2015年7月编程语言排行榜:C++的复兴
- leetcode 日经贴,Cpp code -Binary Tree Preorder Traversal
- 使用GDB调试python调用的C++共享库
- 【C++】struct和class
- 【C++】赋值运算符函数
- C++ next_permutation 穷举每一种组合
- c++builder 重载WindowProc、WndProc 截获消息
- C++中malloc/free与new/delete的区别及内存分配失败错误处理
- 用VS2008编译(zlib)C语言代码的方法
- 【effective c++读书笔记】【第5章】实现(2)
- 【effective c++读书笔记】【第5章】实现(2)
- java借助于JNI调用c/c++动态链接库
- C++黑客编程揭秘与防范之创建一个不会被删除的文件夹
- 如何用C++实现一个LRU Cache
- 详解c++构造函数