【问题标题】:C++ virtual function not found未找到 C++ 虚函数
【发布时间】:2010-08-16 23:01:41
【问题描述】:

我有一个类旨在以几种不同格式之一进行数据的导入/导出。每种格式都应该有完全相同的接口,所以我将它实现为一个基类,其中包含一堆虚拟方法和每个特定格式的派生类:

#ifndef _IMPORTEXPORT_H_
#define _IMPORTEXPORT_H_

#include "stdio.h"

enum EXPORT_TYPE {
    EXPORT_INI = 1,
};

class exportfile {
public: 
    virtual ~exportfile();

    static exportfile * openExportFile(const char * file, EXPORT_TYPE type);

    virtual void startSection(int id) = 0;
    virtual void endSection() = 0;

protected:
    exportfile(const char * file);
    FILE * hFile;

};

class iniexportfile : public exportfile {
public:
    iniexportfile(const char * file) : exportfile(file) { }

    void startSection(int id);
    void endSection();
private:
    bool inSection;

};

#endif

这是基类 (exportfile) 和派生类之一 (iniexportfile)。

这些方法的实现如下:

#include "importexport.h"

#include <exception>
#include <assert.h>

exportfile * openExportFile(const char * file, EXPORT_TYPE type) {
    switch(type) {
        case EXPORT_INI:
            return new iniexportfile(file);
        default:
            return NULL;
    }
}

exportfile::exportfile(const char * file) {

        this->hFile = fopen(file, "w");

        if(this->hFile == 0) {
            throw new std::exception("Unable to open export file");
        }
}

exportfile::~exportfile() {
    assert(this->hFile != 0);

    this->endSection();

    fclose(this->hFile);
    this->hFile = 0;
}

void iniexportfile::startSection(int id) {
    assert(this->hFile != 0);

    fprintf(this->hFile, "[%d]\r\n", id);

    this->inSection = true;
}

void iniexportfile::endSection() {
    this->inSection = false;
}

(注意,这个类显然是不完整的。)

最后,我有一个测试方法:

#include "importexport.h"

#include <exception>

using namespace std;

void runImportExportTest() {
    iniexportfile file("test.ini");

    file.startSection(1);

    file.endSection();
}

无论如何,这一切都编译得很好,但是当它被链接时,链接器会抛出这个错误:

error LNK2001: unresolved external symbol "public: virtual void __thiscall exportfile::endSection(void)" (?endSection@exportfile@@UAEXXZ)   importexport.obj

当它被标记为纯虚拟时,它为什么要寻找exportfile::endSection()?我是不是没有把它变成纯虚拟的?或者,我是不是被 C# 宠坏了,完全搞砸了这些虚函数?

顺便说一句,这是 Visual Studio 2008。我想我应该在某个地方提到这一点。

【问题讨论】:

  • _IMPORTEXPORT_H_reserved identifier
  • @GMan:虽然这是真的,但这与问题无关,对吧?
  • 这就是为什么它是一个评论。 :) (除非您担心这会导致您的代码中断,那么是的,这与您的问题不同。)
  • 不,这不是问题,但使用保留标识符肯定会导致问题。例如,请参阅stackoverflow.com/questions/3345159/…

标签: c++ visual-studio linker virtual-functions


【解决方案1】:

到此 dtor 被调用时:

exportfile::~exportfile() {
    assert(this->hFile != 0);

    this->endSection();

    fclose(this->hFile);
    this->hFile = 0;
}

编译器已“解开”vtable,因此它将解析为exportfile::endSection() 函数 - 它不会调用派生版本。您需要设计一种不同的清理方法。

"Never call virtual functions during construction or destruction"

【讨论】:

  • 磕头 是的,你是对的。该电话应拨入iniexportfile::~iniexportfile。当我这样做时效果很好。
  • 当然,如果我严格地说“我的析构函数中没有虚拟方法”,我会怎么做。将其提取到非虚拟方法中,然后从我的析构函数中调用它?
  • @Mike:问题是有时候做你想做的事情会很好。但我不确定是否有比将所需的清理代码放在每个派生最多的类中更好的模式。
  • @Mike:调用非虚拟方法是可以的,但你将无法做我认为你想做的事情 - 到调用基本析构函数时,没有更多的“派生对象”位可以使用,因此非虚拟函数不能做任何基本析构函数不能做的事情。
  • 我的意思是派生类。所以,private void iniexportfile::cleanupatdestruction() 或类似名称的东西。但是,我将把它留在析构函数中,因为我知道发生了什么。 (实际上,我可以省略它,因为它是一个 nop,但这完全无关紧要)
猜你喜欢
  • 2011-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-07
  • 1970-01-01
  • 2014-06-02
相关资源
最近更新 更多