具有虚函数的未解决外部符号问题

3
我正在尝试通过使用Qt中的设计模式示例来了解虚函数的行为。
在这里,我有一个头文件,其中定义了两个类:
#ifndef ABCLASSES_H
#define ABCLASSES_H
#include <QTextStream>

class A
{
public:
    virtual ~A()
    {

    }
    virtual void foo(QTextStream& out);
    virtual void bar(QTextStream& out);
};

class B: public A
{
public:
    void foo(QTextStream& out);
    void bar(QTextStream& out);
};

#endif // ABCLASSES_H

这是这些类的源文件。
#include "abclasses.h"

void A::foo(QTextStream& out)
{
    out << "A's foo" << endl;
    bar(out);
}

void A::bar(QTextStream& out)
{
    out << "A's bar" << endl;
}

void B::foo(QTextStream& out)
{
    out << "B's foo" << endl;
    A::bar(out);
}

void B::bar(QTextStream& out)
{
    out << "B's bar" << endl;
}

问题是我无法从这些定义中创建或使用任何类。我收到的错误信息是:
main.obj:-1: 错误:LNK2001:未解析的外部符号“public: virtual void __cdecl A::foo(class QTextStream &)”(?foo@A@@UEAAXAEAVQTextStream@@@Z) main.obj:-1: 错误:LNK2001:未解析的外部符号“public: virtual void __cdecl A::bar(class QTextStream &)”(?bar@A@@UEAAXAEAVQTextStream@@@Z)
由于我对虚函数的了解不多,我认为可能需要在B类中重新声明函数,但这也没有帮助,并给我的日志添加了2个错误。
main.obj:-1: 错误:LNK2001:未解析的外部符号“public: virtual void __cdecl B::foo(class QTextStream &)”(?foo@B@@UEAAXAEAVQStream@@@Z) main.obj:-1: 错误:LNK2001:未解析的外部符号“public: virtual void __cdecl B::bar(class QTextStream &)”(?bar@B@@UEAAXAEAVQStream@@@Z)
书中的示例只是在声明后实现函数(在同一文件中),这似乎有效。我想知道为什么我的方法不起作用,是否有解决方法。
编辑: 项目文件使用以下设置:
#-------------------------------------------------
#
# Project created by QtCreator 2015-08-23T11:53:16
#
#-------------------------------------------------

QT       += core

QT       -= gui

TARGET = untitled1
CONFIG   += console
CONFIG   -= app_bundle

TEMPLATE = app


SOURCES += main.cpp \
    student.cpp \
    abclasses.cpp

HEADERS += \
    student.h \
    abclasses.h

我必须说,当涉及到建立、链接东西时,我并没有太多的想法,但对于一个小项目,我现在不应该需要将重点放在这些方面。由于 abclases.cpp 在 sources 中,我认为它在构建过程中被使用。
student.h 和 .cpp 与我在同一项目中进行的另一个尝试有关。它们现在没有被积极使用,下面是 main.cpp。
#include <QCoreApplication>
#include <QTextStream>
//#include "student.h"
#include "abclasses.h"

//void finish(Student& student)
//{
//    QTextStream cout(stdout);
//    cout << "The following " << student.getClassName()
//         << "has applied for graduation" << endl
//         << student.toString() << endl;
//}

int main() {
    QTextStream cout(stdout);
    B bobj;
//    A *aptr = &bobj;
//    aptr->foo(cout);
//    cout << "-------------" << endl;
//    A aobj = *aptr;
//    aobj.foo(cout);
//    cout << "-------------" << endl;
//    aobj = bobj;
//    aobj.foo(cout);
//    cout << "-------------"<< endl;
//    bobj.foo(cout);
}

编辑2:更新过时的错误信息,更新abclasses.h。

B 类中,你必须声明被覆盖的函数。 - Some programmer dude
关于你的问题,你是否实际上是使用包含函数定义的源文件进行构建?我怀疑你也想将B中的这些函数设为public - Some programmer dude
我尝试在B类中的"public:"下声明它们,但正如我所说,这只是让我遇到了另外两个错误。由于我无法有效地使用这个编辑器,因此我正在更新有关“build”部分的问题。 - Mert Can Ergün
听起来 abclasses.cpp 没有被编译和/或链接。你能发布一下“make”的输出吗? - aschepler
尽管我在 Qt 中重建项目之前多次使用了“clean”,但它仍然出现相同的错误。但是在手动删除项目文件夹后,这些错误消失了。感谢您指导我正确的方向。</br>现在我要搜索关于 Qt 清理方法的错误报告。 - Mert Can Ergün
3个回答

1

abclassess.cpp文件未被编译,因为makefile与.pro文件不匹配。在Qt Creator中右键单击最上层项目节点,然后选择Run qmake。之后重新构建该项目。

遗憾的是,在Windows上,Qt Creator与qmake之间存在一个问题。在该平台上,qmake会生成三个makefile:MakefileMakefile.releaseMakefile.debug。不幸的是,只有顶层的makefile与.pro文件之间存在正确的依赖关系:每当项目文件更改时,makefiles将通过调用qmake自动重新生成。通常这不是问题,因为手动构建时,您会在顶层Makefile上调用nmake/jom

但是,Qt Creator会根据需要直接调用Makefile.releaseMakefile.debug来进行发布/调试构建。这将绕过仅存在于基本Makefile中的makefile重新生成规则。正是这种交互导致了这个错误/不良行为,而这个问题(不幸地)目前影响着每个在Windows上使用Qt Creator的用户。
因此,每次更改项目文件后都必须调用qmake - 例如,每次添加或修改源文件时。
有一个简单的解决方法 - 将调用基本Makefile的构建步骤添加到您的项目配置的构建中。

0

请问您能否更新一下问题?因为您说您已经修改了B类,所以请更新一下。即使是新出现的错误也请更新。

private: virtual void __cdecl B::bar(class QTextStream &)" (?

从这个错误来看,B类内部的bar函数似乎是私有的。

0

好的,在搜索互联网寻找类似问题后,这里是结果。 Qt Creator 有时无法确定是否应该更新“make”文件,我有点意识到这一点,因此在进行重大更改后使用“clean”。 但问题是清除或重建并不能完全按照我的要求工作。所以经过一些建议,我手动删除了构建文件夹,现在它可以正常编译和运行。


实际上,Qt Creator 的工作并不是这样的 - Qt Creator 不会更新除了在项目的第一次构建中调用 qmake 之外的任何内容。Makefile 本身应该依赖于项目文件,以便 make 可以自己调用 qmake 来重新生成 Makefile。不幸的是,Creator 调用 Makefile 的方式暴露了 Creator 与 qmake 的不良交互。 - Kuba hasn't forgotten Monica
谢谢您的回答,但我不明白一件事:为什么Qt不需要更新qmake?如果它们的依赖关系没有正确链接,那么每次更改都应该重新构建它。 - Mert Can Ergün
最终,这是一个错误 - 我不知道这是 qmake 的错误还是 Qt Creator 的错误,因为它们在单独使用时都做得很好,但它们的交互是错误的。某个地方需要有人来修复它。即使它被修复了,Qt Creator 也不会直接重新创建任何东西。make 工具会这样做。但现在 make 工具(不是 qmake,也不是 Qt 中的任何东西)没有这样做,因为没有人告诉它要这样做...所以,把它当作一个错误,并采用一个微不足道的解决方法。一旦你配置了你的项目来解决它,你就不会再遇到这个问题了。 - Kuba hasn't forgotten Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接