C ++在构造函数中调用虚方法

时间:2013-11-22 11:31:28

标签: c++ lnk2019 virtual-method

我使用具有一些虚方法的父类。当我在构造函数中调用虚方法时,它会在LNK2019和“LNK1120”消息中出现error LNK2019: unresolved external symbol "protected: virtual int ... referenced in function "public: __thiscall ......\Debug\8puzzleProject.exe : fatal error LNK1120: 1 unresolved externals错误。

有没有办法解决这个问题,或者我不是在构造函数中调用虚方法?

谢谢!

以下是代码:

有错误的类:

#ifndef HEURISTICSEARCH_H
#define HEURISTICSEARCH_H

#include "BruteSearch.h"

class HeuristicSearch: public BruteSearch
{
public:

    HeuristicSearch( int initial[BOARD_LIMIT][BOARD_LIMIT] );
    bool search();

protected:

    virtual int calculateUtility() = 0;
    virtual int calculateUtility( Node* ) = 0;

    bool check4Goal();
    void checkNmove();
    int findMin(int* values );

    int utilityCost;

};

#endif

HeuristicSearch::HeuristicSearch( int initial[BOARD_LIMIT][BOARD_LIMIT] )
    :BruteSearch( initial )
{
    utilityCost = calculateUtility(); //After deleting this line, the error's gone
}

父类的父类(没有错误)

#ifndef BRUTESEARCH_H
#define BRUTESEARCH_H

#include <iostream>
#include <queue>

#include "Constants.h"
#include "Node.h"

class BruteSearch
{
public:

    BruteSearch( int initial[BOARD_LIMIT][BOARD_LIMIT] );
    virtual bool search(){ return false; }

protected:

    bool check4Goal();
    void printBoard();

    int turn;
    int goalBoard[BOARD_LIMIT][BOARD_LIMIT] ;

    Node *currentPtr;

};

#endif

2 个答案:

答案 0 :(得分:6)

  

我不是在构造函数中调用虚方法吗?

这样做会调用正在构造的类中的覆盖,不一定是最终覆盖。这可能不是你想要的,如果函数在当前类中是纯虚函数则会出错,所以通常你不应该这样。

在这种情况下,错误表明它在此类中是纯虚拟的,而未实现,因此调用它肯定是一个错误。幸运的是,它为您提供了一个相当友好的链接器错误,而不是未定义的运行时行为。 (更新:您发布的代码确认猜测 - 您无法从构造函数中调用该函数。)

  

有没有办法解决这个问题

许多问题可以通过额外的间接层来解决。我会在一个单独的委托类中实现启发式,而不是子类:

struct Heuristic {
    virtual ~Heuristic() {}  // Don't forget this on a polymorphic base class
    virtual int calculateUtility() = 0;
    virtual int calculateUtility( Node* ) = 0;
};

class HeuristicSearch: public BruteSearch {
public:
    HeuristicSearch(Heuristic & h, int initial[BOARD_LIMIT][BOARD_LIMIT]) : 
        BruteSearch(initial), 
        heuristic(h),
        utilityCost(heuristic.calculateUtility()) // No problem calling this
    {}

private:
    Heuristic & heuristic;
    int utilityCost;
    // and so on
};

在我们开始构建Search类之前完全构造了委托,因此从构造函数访问它没有任何问题。

或者,为了避免不必要的运行时多态性,我可能会将委托类型作为模板参数注入:

template <class Heuristic>
class HeuristicSearch: public BruteSearch {
public:
    HeuristicSearch(int initial[BOARD_LIMIT][BOARD_LIMIT]) : 
        BruteSearch(initial), 
        utilityCost(heuristic.calculateUtility()) // Doesn't have to be virtual
    {}

private:
    Heuristic heuristic;
    int utilityCost;
    // and so on
};

答案 1 :(得分:2)

构造派生类的对象时,首先构造基类的对象。该对象不知道它将成为派生类的对象。因此,从基类的构造函数调用的任何函数都只针对基类解析,无论函数是否为虚函数。

在您的情况下,HeuristicSearch未提供calculateUtility的实施,但HeuristicSearch::calculateUtility()是从HeuristicSearch的构造函数调用的,无论HeuristicSearch::calculateUtility()是否{{1}}是虚拟还是不虚拟。