繁体   English   中英

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

[英]C++ inheritance not inheriting grandfather file

最近我试图解决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的精确副本,但还有一些额外的东西,但这对我来说真的很愚蠢,这没有任何意义。

我究竟做错了什么?

虽然您的祖先类中有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;

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

computecompute_point的原型添加到Black_White_Mandel

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

例如

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

White_Black_Mandel_Imp1.cpp应该知道它有义务

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

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

有关协变返回类型的覆盖规则,请参阅此问题

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM