0

私は、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;
}
4

2 に答える 2

6

You declare the pure virtual function as taking a ofstream object by value, while all your subclasses define it as taking a reference to one.

virtual void display(std::ostream, ht_sz, bool) const = 0;

vs

void display(std::ostream&, ht_sz, bool) const;
                         ^
于 2013-01-15T04:39:21.903 に答える
4

Pi_base declares display with this signature:

virtual void display(std::ostream, ht_sz, bool) const = 0;

But your derived classes declare it with this signature:

void display(std::ostream&, ht_sz, bool) const;

Compare them closely and you'll see that your base class takes a std::ostream while your derived classes take a std::ostream&.

于 2013-01-15T04:39:34.190 に答える