为什么这些课程不完整?

时间:2014-05-23 07:48:07

标签: c++ oop

我有一个source.C:

#include "image.h"

#ifndef SOURCE_H
#define SOURCE_H

class Source
{
    private:
        Image* img;
    public:
        virtual void Execute()=0;
        Image* GetOutput(); 
};
#endif

Image* Source::GetOutput()
{
    return this->img;
}

和sink.C。

#include "image.h"


#ifndef SINK_H
#define SINK_H
class Sink
{
    private:
        Image* img1;
        Image* img2;

    public:
        void SetInput(Image* input1);
        void SetInput2(Image* input2);
};
#endif

void Sink::SetInput(Image* input1)
{
    this->img1 = input1;
}

void Sink::SetInput2(Image* input2)
{
    this->img2 = input2;
}

我有一个filter.h,我想从Source和Sink继承:

#include "image.h"
#include <iostream>
#include <stdlib.h>

class Source;
class Sink;

class Filter : Source, Sink
{
    public:
        Filter() {std::cout << "Constructing filter." << std::endl;}
};

然而,编译器给出了无效使用不完整类型的错误&#39; class Source&#39;并且&#39;类Sink&#39;。我也得到了相同类的前向声明错误。这些类最初的函数直接在public中定义,所以我把它们移出去了,但这对此没什么帮助。将Public和Sink明确设置为公众也没有帮助。发生了什么事?

4 个答案:

答案 0 :(得分:4)

转发声明只允许编译器知道名称存在,但它不会告诉任何有关名称定义的信息。为了继承,基类&#39;定义必须是已知的。您必须在 filter.h 中包含标头,以便编译器可以看到父类的定义。

修改

声明表示存在名称,定义表示名称的外观。对于类定义,它表示类包含的内容,它的成员,大小等。当一个类被另一个继承时,编译器类基类的成员放在派生类中。所以它必须知道基类是什么样的。通过包含定义基类的头,编译器实际上将定义放在包含的文件中,因此它知道基类。

正如其他人指出您的私下继承一样,我建议您阅读is-a has-a关系和difference between private and public inheritance

答案 1 :(得分:4)

这是因为在你的filter.h中你提出了一个不完整的声明:

class Source;
class Sink;

但没有定义它们。编译器需要知道两者的大小,以便计算Filter的大小:

class Filter : Source, Sink
{
    public:
        Filter() {std::cout << "Constructing filter." << std::endl;}
};

解决方案是包含两者的头文件。为此,您可能需要将声明与源文件和源文件中的实现分开。

答案 2 :(得分:4)

#include "sink.h"
#include "source.h"

应该把你排除在外。

这一行: class Filter : Source, Sink

这是私有继承,几乎总是你不想要的(你不能以多态方式使用该类)。

您可能需要将其更改为

class Filter : public Source, public Sink

答案 3 :(得分:2)

这里有两个问题

第一个,正如其他人所提到的那样,您需要包含Sink和Source的标头。目前,您只有前向声明,它将允许您使用指针,但不能派生或实例化。编译器不知道它提供的大小,方法或构造方法。

第二个问题,一旦包含标题,您将会遇到的问题是Sink类中有一个纯虚函数。这使它成为一个抽象的基类。 你需要从这个(你有)派生并在派生类中实现Execute方法(你没有)