我正在为 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;
}