C++を知りたい(6) OOP Wikiを作る

C++のOOPの勉強をWikiを作りながら行きあたりばったりで進めていますが、大量のコンパイルエラーに何度もめげそうになりました。単純な多態が機能しなくて調べていたところ、下の説明を見付けました。

多態性は、メンバ関数がオーバーライドされており、スーパークラス型の変数がポインタ(または 第15章で登場する「参照」)である必要があります。

C++編(言語解説) 第9章 オーバーライド

これにはかなり驚かされたんですが、C++では常識なんですね。

練習で作っているWiki

(後日説明を追加する予定)

Elementがwikiの文法の1行を表すクラス。Elementを継承したHeadline(見出し)とItem(箇条書き)クラスを定義しました。機能が乏しい状態であるにも関らず、既に泥臭い部分が多いです。まだまだ途中ですが是非添削おねがいします。今後ももうすこしの間は、機能追加をしながらC++のOOPを習得したいと思います。

wiki.hh
#include <vector>
using namespace std;
/**
 * 要素
 */
class Element
{
protected:
string line;
public:
string name;
Element(){};
Element(string l);
virtual ~Element();
virtual string toHtml();
virtual string before();
virtual string after();
};
/**
 * 見出し
 */
class Headline : public Element
{
public:
Headline(string l);
~Headline();
string toHtml();
string before();
string after();
};
/**
 * 箇条書き
 */
class Item : public Element
{
public:
Item(string l);
~Item();
string toHtml();
string before();
string after();
};
/**
 * wikiのページを表すクラス
 */
class Wiki
{
private:
vector<Element*> elements;
string id;
public:
Wiki(string id);
~Wiki();
void output();
};
/**
 * 文法を判定して適切な要素を返す。
 */
Element* elementFactory(string line);
/* vim: set ts=4 sw=4 sts=4 expandtab fenc=utf-8: */
wiki.cc
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include "wiki.hh"
using namespace std;
/**
 * 要素実装
 */
Element::Element(string l)
{
line = l;
name = "Element";
}
Element::~Element()
{
}
string Element::before()
{
string s;
return s;
}
string Element::after()
{
string s;
return s;
}
string Element::toHtml()
{
ostringstream html;
html << "<p>" << line << "</p>" << endl;
return html.str();
}
/**
 * 見出し実装
 */
Headline::Headline(string l)
{
line = l;
name = "Headline";
}
Headline::~Headline()
{
}
string Headline::before()
{
string s;
return s;
}
string Headline::after()
{
string s;
return s;
}
string Headline::toHtml()
{
ostringstream html;
html << "<h1>" << line.substr(1) << "</h1>" << endl;
return html.str();
}
/**
 * 箇条書き実装
 */
Item::Item(string l)
{
line = l;
name = "Item";
}
Item::~Item()
{
}
string Item::before()
{
string s("<ul>\n");
return s;
}
string Item::after()
{
string s("</ul>\n");
return s;
}
string Item::toHtml()
{
ostringstream html;
html << "\t<li>" << line.substr(1) << "</li>" << endl;
return html.str();
}
/**
 * Wiki実装
 */
Wiki::Wiki(string arg_id)
{
id = arg_id;
ostringstream filename_stream;
filename_stream << id << ".txt";
ifstream ifs(filename_stream.str().c_str());
string buf;
while (ifs && getline(ifs, buf)) {
elements.push_back(elementFactory(buf));
}
}
Wiki::~Wiki()
{
unsigned int size = elements.size();
for (unsigned int i = 0; i < size; i++) {
delete elements[i];
}
}
void Wiki::output()
{
cout << "Content-Type: text/html\n\n";
cout << "<html><body>\n";
unsigned int size = elements.size();
for (unsigned int i = 0; i < size; i++) {
if (i > 0 && elements[i - 1]->name != elements[i]->name) {
// 前の要素と異なる場合は、beforeメソッドを呼び出す。
cout << elements[i]->before();
}
cout << elements[i]->toHtml();
if (i < size - 1 && elements[i]->name != elements[i + 1]->name) {
// 次の要素と異なる場合は、afterメソッドを呼び出す。
cout << elements[i]->after();
}
}
cout << "</body></html>\n";
}
Element* elementFactory(string line)
{
if (line.at(0) == '*') {
Headline* h = new Headline(line);
return h;
} else if (line.at(0) == '-') {
Item* i = new Item(line);
return i;
} else {
Element* e = new Element(line);
return e;
}
}
/* vim: set ts=4 sw=4 sts=4 expandtab fenc=utf-8: */

htmlエスケープもまだ実装してません。

index.cc
#include <rude/cgi.h>
#include "wiki.hh"
using namespace std;
int main()
{
rude::CGI cgi;
string id(cgi["id"]);
Wiki wiki(id);
wiki.output();
return 0;
}
/* vim: set ts=4 sw=4 sts=4 expandtab fenc=utf-8: */
Makefile
default: index.cgi
wiki.o: wiki.cc wiki.hh
g++ -Wall -c -o wiki.o wiki.cc
index.o: index.cc
g++ -Wall -c -o index.o index.cc
index.cgi: wiki.o index.o
g++ -o index.cgi index.o wiki.o -lrudecgi
data.txt
*見出し
普通のパラグラフ
-箇条書き1
-箇条書き2
-箇条書き3
普通のパラグラフ
おわり。
実行結果
<html><body>
<h1>見出し</h1>
<p>普通のパラグラフ</p>
<ul>
<li>箇条書き1</li>
<li>箇条書き2</li>
<li>箇条書き3</li>
</ul>
<p>普通のパラグラフ</p>
<p>おわり。</p>
</body></html>

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です


The reCAPTCHA verification period has expired. Please reload the page.

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください