私は、Acellerated c++ の第 15 章のコードをコンパイルする作業を行っています。ヘッダー ファイルのクラス本体でコンストラクターのようなものを定義している場所を除いて、本からコードをそのままコピーしましたが、それらを分離しました。リンクエラーを避けるため。
以下はコードです。Visual Studio 2010 でコンパイルしようとしましたが、残念ながら失敗しました。「String_Pic」およびその他の派生クラス (Frame_Pic、HCat_Pic、および VCat_Pic) はまだ抽象クラスであると表示されているため、それらのインスタンスを作成できないことがわかります。犯人は「表示」機能であり、未定義であると言われています。ただし、以下に示すように、派生クラスごとに明確に定義しています。
何が起きてる?
ヘッダ:
#ifndef _GUARD_PIC_BASE_H
#define _GUARD_PIC_BASE_H
#include "Ptr.h"
#include <iostream>
#include <string>
#include <vector>
class Picture;
class Pic_base {
friend std::ostream& operator<<(std::ostream&, const Picture&);
friend class Frame_Pic;
friend class HCat_Pic;
friend class VCat_Pic;
friend class String_Pic;
typedef std::vector<std::string>::size_type ht_sz;
typedef std::string::size_type wd_sz;
virtual wd_sz width() const = 0;
virtual ht_sz height() const = 0;
virtual void display(std::ostream, ht_sz, bool) const = 0;
public:
virtual ~Pic_base(){ }
protected:
static void pad(std::ostream&, wd_sz, wd_sz);
};
// public interface class and operations
class Picture {
friend std::ostream& operator<<(std::ostream&, const Picture&);
friend Picture frame(const Picture&);
friend Picture hcat(const Picture&, const Picture&);
friend Picture vcat(const Picture&, const Picture&);
public:
Picture(const std::vector<std::string>& =
std::vector<std::string>());
private:
Picture(Pic_base* ptr); //here's one difference
Ptr<Pic_base> p;
};
Picture frame(const Picture&);
Picture hcat(const Picture&, const Picture&);
Picture vcat(const Picture&, const Picture&);
std::ostream& operator<<(std::ostream&, const Picture&);
class String_Pic: public Pic_base {
friend class Picture;
std::vector<std::string> data;
String_Pic(const std::vector<std::string>&);
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};
class VCat_Pic: public Pic_base {
friend Picture vcat(const Picture&, const Picture&);
Ptr<Pic_base> top, bottom;
VCat_Pic(const Ptr<Pic_base>&, const Ptr<Pic_base>&);
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};
class HCat_Pic: public Pic_base {
friend Picture hcat(const Picture&, const Picture&);
Ptr<Pic_base> left, right;
HCat_Pic(const Ptr<Pic_base>&, const Ptr<Pic_base>&);
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};
class Frame_Pic: public Pic_base {
friend Picture frame(const Picture&);
Ptr<Pic_base> p;
Frame_Pic(const Ptr<Pic_base>& pic);
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};
#endif
.cpp/実装ファイル:
#include "Ptr.h"
#include "Pic_Base.h"
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
//Picture-Specific Functions:
Picture::Picture(Pic_base* ptr):p(ptr) {}
Picture::Picture(const vector<string>& v): p(new String_Pic(v)) { }
//Frame-Specific Functions:
Frame_Pic::Frame_Pic(const Ptr<Pic_base>& pic): p(pic) {}
Pic_base::wd_sz Frame_Pic::width() const { return p->width() + 4; }
Pic_base::ht_sz Frame_Pic::height() const { return p->height() + 4; }
void Frame_Pic::display(ostream& os, ht_sz row, bool do_pad) const{
if (row >= height()) {
// out of range
if (do_pad)
pad(os, 0, width());
} else {
if (row == 0 || row == height() - 1) {
// top or bottom row
os << string(width(), '*');
} else if (row == 1 || row == height() - 2) {
// second from fop or bottom row
os << "*";
pad(os, 1, width() - 1);
os << "*";
} else {
// interior row
os << "* ";
p->display(os, row - 2, true);
os << " *";
}
}
}
Picture frame(const Picture& pic){
return new Frame_Pic(pic.p);
}
//HCat-Specific Functions:
HCat_Pic::HCat_Pic(const Ptr<Pic_base>& l, const Ptr<Pic_base>& r): left(l), right(r) { }
HCat_Pic::HCat_Pic(const Ptr<Pic_base>& l, const Ptr<Pic_base>&r):
left(l), right(r) { }
Pic_base::wd_sz width() const { return left->width() + right->width(); }
Pic_base::ht_sz height() const { return max(left->height(), right->heigth()); }
void HCat_Pic::display(ostream& os, ht_sz row, bool do_pad) const{
left->display(os, row, do_pad || row < right->height());
right->display(os, row, do_pad);
}
Picture hcat(const Picture& l, const Picture& r){
return new HCat_Pic(l.p, r.p);
}
//VCat-Specific Functions:
VCat_Pic::VCat_Pic(const Ptr<Pic_base>& t, const Ptr<Pic_base>& b): top(t), bottom(b) { }
Picture vcat(const Picture& t, const Picture& b){
return new VCat_Pic(t.p, b.p);
}
Pic_base::wd_sz VCat_Pic::width() const {
return max(top->width(), bottom->width());
}
Pic_base::ht_sz VCat_Pic::height() const{
return top->height() + bottom->height();
}
void VCat_Pic::display(ostream& os, ht_sz row, bool do_pad) const{
wd_sz w = 0;
if (row < top->height()) {
// we are in the top subpicture
top->display(os, row, do_pad);
w = top->width();
} else if (row < height()) {
// we are in the bottom subpicture
bottom->display(os, row - top->height(), do_pad);
w = bottom->width();
}
if (do_pad)
pad(os, w, width());
}
//String_Pic-Specific Functions:
String_Pic::String_Pic(const std::vector<std::string>& v): data(v) { }
Pic_base::ht_sz String_Pic::height() const { return data.size(); }
Pic_base::wd_sz String_Pic::width() const{
Pic_base::wd_sz n = 0;
for (Pic_base::ht_sz i = 0; i != data.size(); ++i)
n = max(n, data[i].size());
return n;
}
void String_Pic::display(ostream& os, ht_sz row, bool do_pad) const{
wd_sz start = 0;
// write the row if we're still in range
if (row < height()) {
os << data[row];
start = data[row].size();
}
// pad the output if necessary
if (do_pad)
pad(os, start, width());
}
//Pic_base-Specific functions:
void Pic_base::pad(std::ostream& os, wd_sz beg, wd_sz end) {
while (beg != end) {
os << " ";
++beg;
}
}
//Non-Specific Functions:
ostream& operator<<(ostream& os, const Picture& picture){
const Pic_base::ht_sz ht = picture.p->height();
for (Pic_base::ht_sz i = 0; i != ht; ++i) {
picture.p->display(os, i, false);
os << endl;
}
return os;
}