问候所有人,
我来自Java背景,我在多重继承方面遇到了困难。
我有一个名为IView的接口,它有init()方法。我想派生一个名为PlaneViewer的新类,实现上面的接口并扩展另一个类。 (QWidget的)。
我的实施如下:
IViwer.h(只有首页文件,没有CPP文件):
#ifndef IVIEWER_H_
#define IVIEWER_H_
class IViewer
{
public:
//IViewer();
///virtual
//~IViewer();
virtual void init()=0;
};
#endif /* IVIEWER_H_ */
我的派生班。
PlaneViewer.h
#ifndef PLANEVIEWER_H
#define PLANEVIEWER_H
#include <QtGui/QWidget>
#include "ui_planeviewer.h"
#include "IViewer.h"
class PlaneViewer : public QWidget , public IViewer
{
Q_OBJECT
public:
PlaneViewer(QWidget *parent = 0);
~PlaneViewer();
void init(); //do I have to define here also ?
private:
Ui::PlaneViewerClass ui;
};
#endif // PLANEVIEWER_H
PlaneViewer.cpp
#include "planeviewer.h"
PlaneViewer::PlaneViewer(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
}
PlaneViewer::~PlaneViewer()
{
}
void PlaneViewer::init(){
}
我的问题是:
2.我无法编译上面的代码,给出错误:
PlaneViewer] + 0x28):对IViewer的'typeinfo'的未定义引用 collect2:ld返回1退出状态
我是否必须在CPP文件中实现IView(因为我想要的只是一个接口而不是实现)?
答案 0 :(得分:7)
考虑接口类的一个好方法是它们指定派生类必须实现的方法。
是否有必要声明方法 PlaneViewer接口中的init()也是, 因为它已经定义了 IVIEW?
快速回答是,您必须在IViewer
中实现init方法,因为在基类中,该方法被声明为纯虚拟。这意味着任何派生类必须提供自己的方法实现,因为没有实现基类方法。
2.我无法编译上面的代码,给出错误:
PlaneViewer] + 0x28):未定义 对IViewer的'typeinfo'的引用 collect2:ld返回1退出状态
这是一个g ++编译器错误,它指示(如上所述)你有一个来自具有纯虚函数的基类的派生类,并且派生类没有实现纯虚方法,因为它必须。
哦,还应该注意的是,您没有多重继承问题,如果仅涉及IViewer
和PlaneViewer
,问题仍然存在。
答案 1 :(得分:4)
是的,您还必须在init
中声明PlaneViewer
。如果您没有,那么init
中PlaneViewer
将不存在,而PlaneViewer
仍然会被视为抽象(因为init
没有实现)。
您需要在IViewer
中为(虚拟)析构函数定义空体。 C ++中的“接口”并不是真正的接口,只是按照惯例,您创建一个包含所有纯虚方法且没有字段的类:但是,从编译器的角度来看,它们仍然只是“常规”类,所以你仍然需要提供析构函数的实现。
class IViewer
{
public:
IViewer() { }
virtual ~IViewer() { }
virtual void init() = 0;
};
答案 2 :(得分:3)
是否有必要在PlaneViewer接口中声明方法init(),因为它已经在IView中定义了?
您不必在PlaneViewer中声明init(),但如果不这样,PlaneViewer将是一个抽象类,这意味着您无法实例化它。
如果你的意思是问你是否必须'void init();'在PlaneViewer的头文件和.cpp文件中。答案是肯定的。
我无法编译上面的代码,给出错误: PlaneViewer] + 0x28):对IViewer的'typeinfo'的未定义引用'collect2:ld返回1退出状态
我认为你要么没有构建相同的代码,要么你的编译命令不正确。
我删除了QT的东西,并且能够使用g ++构建你的代码。
错误意味着链接器找不到IViewer类。
如果我删除使'IViewer :: init()'成为纯虚函数的'= 0'部分,我会收到该错误。如果在IViewer中取消注释构造函数和/或析构函数,也可能会出现该错误。
我是否必须在CPP文件中实现IView?
没有。 C ++不关心它是在.cpp文件还是.h文件中。与Java不同,C / C ++预处理器首先解析所有包含并生成包含所有代码的文件。然后它将它传递给C / C ++编译器。如果需要,您实际上可以包含.cpp。不过不是一个好主意。
答案 3 :(得分:3)
typeinfo问题是由于没有为IViewer类实现析构函数引起的。通常,编译器将生成内部数据结构(例如“typeinfo”)以及虚拟析构函数。
您需要编译并链接包含以下内容的文件:
#include "iviewer.h"
IViewer::~IViewer() { }
最好有一个虚拟析构函数,因为这为编译器提供了一个使用RTTI信息的编译单元,它还允许delete操作符在基类指针上调用时正常工作。
其他人已回答关于init()方法的问题,但总结如下:如果要在PlaneViewer中实现它,则需要声明它。
答案 4 :(得分:2)
是的,您需要在子类中重新声明virtual void init()
并实现它,因为IViewer
将该函数声明为纯虚函数。
有关错误的说明,请参阅another question。它是由声明虚函数(不纯)而不是定义它引起的。从您发布的代码中看不出来,所以我怀疑您可能有未重建的过时目标文件(您已注释掉IViewer
构造函数和虚拟析构函数)。
另外请注意you should provide virtual destructors with empty body for your interfaces。
答案 5 :(得分:2)
我已经完成了两种语言的重要工作,并且通常可以使用cookie切割器模式将Java接口转换为c ++接口:
//从Java接口开始
interface Numeric {
public int toInteger();
public double toDouble();
};
C ++早于Java,并且不需要定义特殊的&#34;接口&#34;纯虚拟类的关键字。因此,您必须有效地完成Java编译器自动执行的一些工作:
//等效的C ++类
class Numeric {
private:
Numeric(const Numeric&);
Numeric& operator=(const Numeric&);
public:
Numeric() {}
virtual ~Numeric() {}
virtual int toInteger() = 0;
virtual double toDouble() = 0;
};
在C ++中遵循的另一条好规则是,无论何时从具有纯虚方法的基类继承,即使将它们保留为纯虚拟,也要在派生类中重新声明它们。它不会损害性能,它让每个人都知道该对象只是部分实现。