1 我的简单模拟
Code:
- template<typename T>
- class stack
- {
- public:
- void push(T const& elem);
- void pop();
- T top()const;
- bool empty()const
- {
- return _stack.empty();
- }
- T& operator[](int i)
- {
- return _stack[i];
- }
- bool operator == (stack& rhs)
- {
- return _stack == rhs._stack;
- }
- friend bool operator != (stack& lhs,stack& rhs);
- friend bool operator < (stack& lhs,stack& rhs);
- friend bool operator <= (stack& lhs,stack& rhs);
- friend bool operator > (stack& lhs,stack& rhs);
- friend bool operator >= (stack& lhs,stack& rhs);
- private:
- vector _stack;
- };
- template<typename T>
- void stack::push(T const& elem)
- {
- _stack.push_back(elem);
- }
- template<typename T>
- void stack::pop()
- {
- if (_stack.empty())
- {
- throw out_of_range("stack<>::pop():empty stack");
- }
- _stack.pop_back();
- }
- template<typename T>
- T stack::top()const
- {
- if (_stack.empty())
- {
- throw out_of_range("stack<>::pop():empty stack");
- }
- return _stack.back();
- }
- template<typename T>
- bool operator != (stack& lhs,stack& rhs)
- {
- return !(lhs == lhs);
- }
- template<typename T>
- bool operator < (stack& lhs,stack& rhs)
- {
- return lhs._stack < rhs._stack;
- }
- template<typename T>
- bool operator <= (stack& lhs,stack& rhs)
- {
- return lhs._stack <= rhs._stack;
- }
- template<typename T>
- bool operator > (stack& lhs,stack& rhs)
- {
- return !(lhs <= rhs);
- }
- template<typename T>
- bool operator >= (stack& lhs,stack& rhs)
- {
- return !(lhs < rhs)
- }
2 《C++ STL中文版》上栈的源码
Code:
- #include
- #include
- #include
- #include
- #include
- using namespace std;
- template < typename T,typename C = deque >
- class stack
- {
- public:
- typedef typename C container_type;
- typedef typename C::value_type value_type;
- typedef typename C::size_type size_type;
- explicit stack(const C& cont):_stack(cont){}
- stack():_stack(){}
- bool empty()const{return (_stack.empty());}
- size_type size()const{return (_stack.size());}
- value_type& top(){return (_stack.back());}
- const value_type& top()const{return (_stack.back());}
- void push(const value_type& elem)
- {
- _stack.push_back(elem);
- }
- void pop()
- {
- _stack.pop_back();
- }
- bool Eq(const stack& X)const
- {
- return (_stack == X._stack);
- }
- bool Lt(const stack& X)const
- {
- return (_stack < X._stack);
- }
- protected:
- deque _stack;
- };
- template <typename T,typename C>
- inline bool operator == (const stack& lhs,const stack& rhs)
- {
- return lhs.Eq(rhs);
- }
- template <typename T,typename C>
- inline bool operator != (const stack& lhs,const stack& rhs)
- {
- return !(lhs == rhs);
- }
- template <typename T,typename C>
- inline bool operator < (const stack& lhs,const stack& rhs)
- {
- return lhs.Lt(rhs);
- }
- template <typename T,typename C>
- inline bool operator > (const stack& lhs,const stack& rhs)
- {
- return rhs < lhs;
- }
- template <typename T,typename C>
- inline bool operator <= (const stack& lhs,const stack& rhs)
- {
- return !(rhs < lhs);
- }
- template <typename T,typename C>
- inline bool operator >= (const stack& lhs,const stack& rhs)
- {
- return !(lhs < rhs);
- }
- int main()
- {
- typedef allocator<char> Myal;
- typedef deque<char,Myal> Myimpl;
- typedef stack<char,Myimpl> Mycont;
- typedef list<char,Myal> Myimpl2;
- typedef stack<char,Myimpl2> Mycont2;
- typedef vector<char,Myal> Myimpl3;
- typedef stack<char,Myimpl3> Mycont3;
- Mycont::container_type *p_cont = (Myimpl *)0;
- Mycont::value_type *p_val = (char *) 0;
- Mycont::size_type *p_size = (size_t *)0;
- Mycont v0(Myimpl(3,'x')),v0a;
- Mycont2 v1;
- Mycont3 v2;
- assert(v0.size() == 3 && v0.top() == 'x');
- assert(v0a.empty());
- v0 = v0a;
- v0.push('a');
- assert(v0.size() == 1 && v0.top() == 'a');
- v0.push('b');
- assert(v0.size() == 2 && v0.top() == 'b');
- v0.push('c');
- assert(v0.size() == 3 && v0.top() == 'c');
- assert(v0 == v0 && v0a < v0);
- assert(v0 != v0a && v0 > v0a);
- assert(v0a <= v0 && v0 >= v0a);
- v0.pop();
- assert(v0.top() == 'b');
- v0.pop();
- assert(v0.top() == 'a');
- v0.pop();
- assert(v0.empty());
- cout << "SUCCESS testing " << endl;
- system("pause");
- return 0;
- }
3 我的程序与源码的对比
① 就整体模板而言
源码就比我稍胜一筹,它给用户提供了更多的选择,即容许用户提供自己的容器类型,并且源码还提供了默认的容器类型。即:双端队列。
② 从效率而言
源码基本上把所有的函数均定义为了内敛函数,并且这些函数也符合内敛的规则。而我的函数大部分都别我定义成了友元函数。效率上应该不如源码。
③ 从封装性而言
源码的封装性比我的好,因为我的大部分函数均定义为了友元,这样就降低了类的封装性,而源码的实现方法比较好,它仅仅为类增加了两个成员函数,然后其他的函数均在类外通过对象调用这两个函数来实现功能。封装性提升了。
④ 就功能而言
源码的功能定时齐全了,不但栈的所有功能均已实现,还为栈定义了几种类型,如栈内容器类型,元素类型,大小类型等。
⑤ 成员的属性
容器在我的程序中为私有成员,而在源码中为保护成员,看似源码在为其它类派生该类做了准备。这确实考虑周到,真没想到这点。
⑥ 我的优点
源码唯一没有用的就是异常,并且在入栈或是返回栈顶元素的时候没有进行栈空检验(这里应该抛出一个out_of_range();异常),我觉得这点很重要,应该有个提示语告诉用户,否则用户还不知道发生了什么事情呢。。
总结:
1 在写程序时应该注意时常站在用户的角度去考虑问题,要一切为用户,方便用户。毕竟它是才真正使用我们的设计的人,应该让我们的接口易于使用,不容易被误用。另:接口应该符合用户的习惯,如求大小的size(),求栈顶的top()这些都是用户习惯了的函数,若我们冒然改变,用户定是很是不习惯,难免会有抱怨。。
2 在功能的设计上应该齐全,同样要站在用户的角度,考虑用户会用到那些功能,以及这些功能常用的函数名是什么。
3 在效率上,应该时刻考虑到效率的存在,不能只为功能而设计,效率却也很重要。
4 在类的封装性啊。类的封装性是C++里一个重要的性质,也是面向对象的一个重要性质,这个不能忽略,应该时刻考虑到封装性,若是封装性都给忽略了,一切为了设计而设计,那和面向过程也快没什么区别了。。
5 在错误判断上,对于一个功能的设计,我们应该时刻考虑到用户会犯的错误以及处理的办法。或是警告用户错误的地方并推出程序,或是给用户一个选择的机会等。否则用户会为这莫名奇妙的错误而犯愁呢。。呵呵。。
6 代码的复用性
应该考虑到代码的复用性,不能只为设计而设计,在实际工作呢。。用到以前的模块或是代码应该是很有很能的,而在C++中的复用性有: 1 类的继承,即我们可以继承一个已有的类,来复用已有类的接口或是成员,2 组合 我们可以将一个已有类的对象作为新类的一个成员来复用 3 函数复用,模块复用 等。。。故复用性也很重要不可忽略。