在对容器类Stack和Stash的描述中,有一点是重复出现的,这就是 所有权问题。
在第14章的例子InheritStack.cpp中提出了一种解决办法,从Stack继承出
一个仅可以接收和生成string指针的类
问题是我们希望容器可以容纳更多的类型,但我们不想使用void指针
这种方法使用单根继承或基于对象的继承。可以看到使用单根继承还有其他
一些优点
为了解决所有权问题,可以创建一个相当简单的类Object作为基类,它仅
包含一个虚析构函数
//: C15:OStack.h
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
// Using a singly-rooted hierarchy
#ifndef OSTACK_H
#define OSTACK_H
class Object {
public:
virtual ~Object() = 0;
};
// Required definition:
inline Object::~Object() {}
class Stack {
struct Link {
Object* data;
Link* next;
Link(Object* dat, Link* nxt) :
data(dat), next(nxt) {}
}* head;
public:
Stack() : head(0) {}
~Stack(){
while(head)
delete pop();
}
void push(Object* dat) {
head = new Link(dat, head);
}
Object* peek() const {
return head ? head->data : 0;
}
Object* pop() {
if(head == 0) return 0;
Object* result = head->data;
Link* oldHead = head;
head = head->next;
delete oldHead;
return result;
}
};
#endif // OSTACK_H ///:~
通过把所有的东西放在头文件中来简化问题,纯虚析构函数的定义以内联
形式置于头文件中,并且pop()也是内联的
Link对象现在是指向Object指针,而不是void指针,并且Stack也将仅仅接收
和返回Object指针
//: C15:OStackTest.cpp
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
//{T} OStackTest.cpp
#include "OStack.h"
#include "../require.h"
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
// Use multiple inheritance. We want
// both a string and an Object:
class MyString: public string, public Object {
public:
~MyString() {
cout << "deleting string: " << *this << endl;
}
MyString(string s) : string(s) {}
};
int main(int argc, char* argv[]) {
requireArgs(argc, 1); // File name is argument
ifstream in(argv[1]);
assure(in, argv[1]);
Stack textlines;
string line;
// Read file and store lines in the stack:
while(getline(in, line))
textlines.push(new MyString(line));
// Pop some lines from the stack:
MyString* s;
for(int i = 0; i < 10; i++) {
if((s=(MyString*)textlines.pop())==0) break;
cout << *s << endl;
delete s;
}
cout << "Letting the destructor do the rest:"
<< endl;
getchar();
} ///:~
从10个元素从栈中弹出,这意味着还保留了一些对象
创建包容Object的容器是一种合理的方法--如果使用单根继承
输出
} ///:~
deleting string: } ///:~
getchar();
deleting string: getchar();
<< endl;
deleting string: << endl;
cout << "Letting the destructor do the rest:"
deleting string: cout << "Letting the destructor do the rest:"
}
deleting string: }
delete s;
deleting string: delete s;
cout << *s << endl;
deleting string: cout << *s << endl;
if((s=(MyString*)textlines.pop())==0) break;
deleting string: if((s=(MyString*)textlines.pop())==0) break;
for(int i = 0; i < 10; i++) {
deleting string: for(int i = 0; i < 10; i++) {
MyString* s;
deleting string: MyString* s;
Letting the destructor do the rest: