C++ Извикване на виртуален метод в Constructor

Използвам родителски клас, който има някои виртуални методи. Когато извикам виртуалния метод в конструктора, той дава 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

person ciyo    schedule 22.11.2013    source източник
comment
може ли да публикувате кода си? Използвате ли своя родителски клас сам? Няма да работи без предоставяне на внедряването на виртуални методи.   -  person nio    schedule 22.11.2013
comment
възможен дубликат на Извикване на виртуални функции в конструктори   -  person Kiril Kirov    schedule 22.11.2013


Отговори (2)


не трябва ли да извикам виртуален метод в конструктора?

Това ще извика замяната в класа, който се конструира, не непременно окончателната замяна. Това вероятно не е това, което искате, и е грешка, ако функцията е чисто виртуална в текущия клас, така че по принцип не трябва.

В този случай грешката предполага, че е чисто виртуална и не е внедрена в този клас, така че извикването й определено е грешка. За щастие ви даде сравнително приятелска грешка на свързване, а не недефинирано поведение по време на изпълнение. (АКТУАЛИЗАЦИЯ: кодът, който сте публикували, потвърждава това предположение - не можете да извикате функцията от конструктора).

Има ли начин да се реши този проблем

Много проблеми могат да бъдат решени с допълнително ниво на индиректност. Бих приложил евристика в отделен делегатен клас, а не в подклас:

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
};
person Mike Seymour    schedule 22.11.2013
comment
Да, това е чисто виртуална функция и я прилагам в часовете на децата. Така че, предполагам, получих отговора. - person ciyo; 22.11.2013

Когато конструирате обект от производен клас, първо се конструира обект от базовия клас. Този обект не знае, че ще стане обект на производния клас. Следователно всички функции, които се извикват от конструктора на базовия клас, се разрешават само спрямо базовия клас, независимо дали функцията е виртуална или не.

Във вашия случай HeuristicSearch не предоставя имплементация на calculateUtility, но HeuristicSearch::calculateUtility() се извиква от конструктора на HeuristicSearch, независимо дали HeuristicSearch::calculateUtility() е виртуален или не.

person Oswald    schedule 22.11.2013