C ++继承不继承祖父文件

时间:2013-03-15 00:21:46

标签: c++ inheritance polymorphism

最近我试图解决C ++继承和多态,但我有一些问题对我没用。 我在单独的文件中有2个头文件和一个带有实现的cpp文件。我的代码的简短摘要如下:

#ifndef MANDEL_H_
#define MANDEL_H_

class Mandel{

public:
    virtual void compute("various arguments") = 0;

    //dummy destructor, I must have one or compile is sad and I dunno why
    virtual ~Mandel();
private:
    virtual int compute_point("various arguments") = 0;
};

#endif

这是我的“祖父”标题“Mandel.h”。现在转移到“父亲”标题。下一个标题指定了一些特定于Mandel的白色和黑色实现的变量,称为“Black_White_Mandel.h”:

#ifndef BLACK_WHITE_MANDEL_H_
#define BLACK_WHITE_MANDEL_H_

#include "Mandel.h"

class Black_White_Mandel: public Mandel {

protected:
    int max_iterations; //a specific variable of this Black_White Version
};

#endif

现在,在一个名为White_Black_Mandel_Imp1.cpp的单独文件中执行Black_White_Mandel标头:

#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#include "Mandel.h"
#include "Black_White_Mandel.h"

using namespace std;

//constructor
Black_White_Mandel::Black_White_Mandel(){
    max_iterations = 255;
}

//destructor
Black_White_Mandel::~Black_White_Mandel(){}

int Black_White_Mandel::compute_point("various arguments") {
    //code and stuff
    return 0;
}

void Black_White_Mandel::compute("various arguments") {
     //code and stuff
}

因此,Mandel.h必须实现2个函数,因为它们是虚拟的并且“= 0”。在White_Black_Mandel_Imp1.cpp中,当我实现编译器疯狂的那些函数时。它说函数没有在White_Black_Mandel.h中定义,尽管如此,它们在Mandel.h中定义。因此,通过继承,White_Black_Mandel_Imp1.cpp应该知道它有从Mandel.h实现这些函数的义务。

我不明白,我的一个朋友说我的White_Black_Mandel.h文件应该是Mandel.h的精确副本,但还有一些额外的东西,但这对我来说真的很愚蠢,这没有任何意义。

我做错了什么?

5 个答案:

答案 0 :(得分:7)

虽然您的祖先类中有2个纯虚方法,但这并不意味着它们的原型可以在子类中使用。

您必须在您的子类中声明原型:

class Black_White_Mandel: public Mandel {

public:
    virtual void compute("various arguments")

protected:
    int max_iterations; //a specific variable of this Black_White Version

private:
    virtual int compute_point("various arguments");
};

virtual关键字是可选的,但知道该方法确实是虚拟的很有用。你没有被迫在这个特定的子类中实现它们,你可以避免指定任何东西,但你仍然有两个必须实现的纯虚方法,所以你将无法实例化这个子类的任何对象(你将有无论如何在层次结构树中实现它们。)

虚拟析构函数是必需的,否则在类似的情况下:

Base *derived = new Derived();
delete derived;

编译器无法调用正确的析构函数。

答案 1 :(得分:4)

computecompute_point的原型添加到Black_White_Mandel

在某些情况下,您从具有纯虚函数的基类继承并且未实现所有这些函数:您的派生类将保持抽象,并且需要继承自另一个类等,直到所有纯虚函数实施。

E.g。

class A {
    virtual void foo() = 0;
    virtual void bar() = 0;
};

class B : public A {
    virtual void foo() {};
};

class C : public B {
    virtual void bar() {};
};

class D : public A {
    virtual void foo() {};
    virtual void bar() {};
};

上面唯一可实例化的类是CD

答案 2 :(得分:3)

  

White_Black_Mandel_Imp1.cpp应该知道它有义务

它不会也不应该。它也可以决定是一个抽象类,在这种情况下它可以单独留下这些函数。

答案 3 :(得分:3)

必须在实现类中提供声明的原因是,派生类使用不同的返回类型覆盖虚函数是合法的,只要新的返回类型为< em> covariant 与原始返回类型。例如,您的基类可以返回BaseReturnedObject&,但您的派生类可以选择返回DerivedReturnObject&。如果派生类中没有声明,编译器就不知道方法的返回类型是什么。它不能假设它与基数相同,因此编译器需要原型。

有关使用协变返回类型的覆盖规则,请参阅this question

答案 4 :(得分:0)

想象一下,你的“祖父”课程中有4种方法,所有方法都是纯虚拟的。现在,您打算在“父”类中实现两个,在“子”类中实现两个。顺便说一下,这个特殊的术语并不理想,但我坚持认为它是因为你开始使用它。

当您定义类时(在class whatever {};之间的.h文件中,您告诉编译器您打算覆盖基类(术语中的祖父类)中的哪些函数。您可以将实现放在标题中,也可以将其放在.cpp文件中。但是您必须指定要覆盖的4个函数(如果有)中的哪一个。

如果你没有在类定义中提到一个特定的继承函数(正如你所说的那样在头文件中),那么当需要编译实现(.cpp文件)时,编译器会说 < em>“什么?你从来没有告诉我你打算覆盖这个功能!” 你的回答似乎是 “老兄,如果我不覆盖它,它是纯虚拟的我无法实例化对象!“ ,但你知道吗?编译器对此并不在意。它不知道你是否想要创建一个可实例化的对象,如果你打算进一步继承,或者甚至真的认为该函数是基类中的纯虚函数。它只知道是,它正在编译一个实现文件,它遇到了一个你在类定义中没有告诉它的函数。

因此,当您编写class something { ... };类定义时,请确保列出您要为该类实现的所有函数,无论您是否继承它们。不要列出您继承的功能,并且不会实现。如果你继承的是一个接口(所有的功能都是纯虚拟的)那么是的,如果你要全部实现它们,你必须在课堂上列出它们。那是因为语言没有为这种情况留出特殊情况。这完全不等同于“我的标题必须是祖父类头文件的精确副本”,我认为如果你在祖父类中有更多的功能,并且没有实现它们,你会更清楚地看到它所有在儿童班。