c++ - 编译器将派生类视为实际定义的抽象引用函数

标签 c++ abstract-class instantiation

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

最佳答案

您将纯虚函数声明为采用 ofstream 按值获取对象,而您所有的子类都将其定义为获取对一个对象的引用 .

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

对比

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

关于c++ - 编译器将派生类视为实际定义的抽象引用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14331244/

相关文章:

c++ - 前向声明的替代方案 : two classes using each other

c++ - 模板的私有(private)静态变量成员的 undefined symbol

c++ - 将 std::vector 分配给堆上特定内存位置的正确语法?

c++ - 命名互斥体的不同句柄结果

java - 为什么我们需要Java中的抽象类?

java - python 是否具有与 Java Class.forName() 等效的功能?

java - 如何从包含 HashMap 实例的抽象类实例化新对象?

c++ - unique_lock 可以与 recursive_mutex 一起使用吗?

c++ - 我可以将一个随机引擎分配给一个变量而无需到处都有模板变量吗?

c++ - 在抽象基类中重载运算符的正确方法是什么?