lnk2001和lnk2019错误

时间:2014-09-14 15:32:14

标签: c++ visual-studio-2010 lnk2019 lnk2001

我想先说这个问题,这是我第一次提出我已经提出的问题;如果我遗漏了你们需要的东西,请告诉我。

过去几天我一直在梳理我在互联网上找到的所有内容,而我似乎无法弄清楚我需要做些什么来解决这些错误。这些文件都是同一个项目的一部分。我也在使用QT。我也意识到我的代码中可能存在逻辑错误。在我运行任何测试之前,我遇到了这些链接器错误。

错误:

error LNK2001: unresolved external symbol "private: static class RadixTree<class ConsoleWidget::FunctionWrapper> ConsoleWidget::mCommands" (?mCommands@ConsoleWidget@@0V?$RadixTree@VFunctionWrapper@ConsoleWidget@@@@A)
error LNK2019: unresolved external symbol "public: bool __cdecl RadixTree<class ConsoleWidget::FunctionWrapper>::Insert(char const *,class ConsoleWidget::FunctionWrapper *)" (?Insert@?$RadixTree@VFunctionWrapper@ConsoleWidget@@@@QEAA_NPEBDPEAVFunctionWrapper@ConsoleWidget@@@Z) referenced in function "public: __cdecl ConsoleWidget::ConsoleWidget(void)" (??0ConsoleWidget@@QEAA@XZ)
error LNK2019: unresolved external symbol "public: class ConsoleWidget::FunctionWrapper * __cdecl RadixTree<class ConsoleWidget::FunctionWrapper>::Contains(char *)" (?Contains@?$RadixTree@VFunctionWrapper@ConsoleWidget@@@@QEAAPEAVFunctionWrapper@ConsoleWidget@@PEAD@Z) referenced in function "public: __cdecl ConsoleWidget::ConsoleWidget(void)" (??0ConsoleWidget@@QEAA@XZ)

对于代码墙感到抱歉,我想我应该只包含相关文件中的所有内容。 = /

RadixTree.h

#ifndef RADIX_TREE
#define RADIX_TREE

#define numStorableChars 26

template<class Value> class RadixTree{
  class Node{
  public:
    char* mStringPart;
    Node* mNextNodes[26];
    Value* mValue;
    Node(){ 
      mStringPart = 0;
      mValue = 0;
      mNextNodes = 0;
    }
  };

public:
  RadixTree();
  ~RadixTree();
  Value* Contains(char* key);
  bool Insert(const char* key, Value* value);
private:
  Node* mRoot;
  void deleteTree(Node* node);
};

#endif

RadixTree.cpp

#include <RadixTree.h>

template<class Value> RadixTree<Value>::RadixTree(){ mRoot = new Node(); }

template<class Value> RadixTree<Value>::~RadixTree(){ deleteTree(mRoot); }

template<class Value> void RadixTree<Value>::deleteTree(Node* node){
  delete node->mStringPart;
  delete node->mValue;
  if(node->mNextNodes){
    for(int i = 0; i < numStorableChars; i++){
      if(node->mNextNodes[i])
        deleteTree(node->mNextNodes[i]);
    }
    delete node->mNextNodes;
  }
  delete node;
}

template<class Value> Value* RadixTree<Value>::Contains(char* key){
  Node* temp = mRoot;
  while(*key != '\0'){
    //////////////////////////////////////////////////////////////////////////
    //Check the index of the Node array
    if(*key < 97 || *key > 122) return 0; //check for valid character
    if(!temp->mNextNodes[*key - 97]) return 0; //check that node exists

    temp = temp->mNextNodes[*key - 97];
    key++;
    //////////////////////////////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////////////////
    //Check the string part the node represents
    if(temp->mStringPart){
      char* stringIter = temp->mStringPart;
      while(*key != '\0' && *stringIter != '\0'){
        if(*key != *stringIter) return 0; //Not in tree
        key++;
        stringIter++;
      }
      if(*key == '\0' && *stringIter == '\0') break; //Found what we were looking for
      if(*stringIter != '\0') return 0; //Not in tree
    }
    //////////////////////////////////////////////////////////////////////////
  }
  return temp->mValue;
}

template<class Value> bool RadixTree<Value>::Insert(const char* key, Value* value){
  Node* temp = mRoot;
  Node* prevTemp = temp;

  //check for valid characters
  char* keyIter = key;
  while(*keyIter != '\0'){
    if(*keyIter < 97 || *keyIter > 122) return false; 
    keyIter++;
  }
  keyIter = key;
  char* prevKeyIter = 0;

  while(true){
    //////////////////////////////////////////////////////////////////////////
    //Does the way we want to go have a node?
    if(!temp->mNextNodes[*keyIter - 97]){ //if not, make one and we're done
      temp->mNextNodes[*keyIter - 97] = new Node[26];
      temp->mNextNodes[*keyIter - 97]->mValue = value;
      if(*(keyIter++) != '\0') strncpy(temp->mNextNodes[*keyIter - 97]->mStringPart, keyIter, strlen(keyIter));
      return true; 
    }
    //////////////////////////////////////////////////////////////////////////

    prevTemp = temp;
    temp = temp->mNextNodes[*keyIter - 97];
    prevKeyIter = keyIter;
    keyIter++;

    //////////////////////////////////////////////////////////////////////////
    //Check the string part the node represents
    if(temp->mStringPart){
      char* stringPart = temp->mStringPart;
      //char* prevStringPart = stringPart;
      while(true){
        if(*keyIter == '\0' && *stringPart == '\0'){//We found the node we were looking for
          if(temp->mValue) return false;//There is something already here; we are done
          else { //We can insert the value and be done
            temp->mValue = value;
            return true;
          }
        } else if(*keyIter != '\0' && *stringPart == '\0') break; //We need to go deeper
        else if(*keyIter == '\0' && *stringPart != '\0'){//We need to split strings and insert a node
          Node* newNode = new Node();
          newNode->mValue = value;
          if(stringPart - temp->mStringPart != 0)
            strncpy(newNode->mStringPart, temp->mStringPart, stringPart - temp->mStringPart);
          newNode->mNextNodes[*stringPart] = temp;
          if(*(stringPart + 1) == '\0'){//Is there anything left after cutting up the string
            delete temp->mStringPart;
            temp->mStringPart = 0;
          } else {
            char* tempChar = temp->mStringPart;
            strncpy(temp->mStringPart, stringPart + 1, strlen(stringPart + 1));
            delete tempChar;
          }
          prevTemp->mNextNodes[*prevKeyIter] = newNode;
        } else {//(*keyIter != '\0' && *stringPart != '\0') //Keep checking the strings
          if(*keyIter != *stringPart){//We need to split strings and insert a node
            Node* newNode = new Node();
            //newNode->mValue = value;
            if(stringPart - temp->mStringPart != 0)
              strncpy(newNode->mStringPart, temp->mStringPart, stringPart - temp->mStringPart);
            newNode->mNextNodes[*stringPart] = temp;
            if(*(stringPart + 1) == '\0'){//Is there anything left after cutting up the string
              delete temp->mStringPart;
              temp->mStringPart = 0;
            } else {
              char* tempChar = temp->mStringPart;
              strncpy(temp->mStringPart, stringPart + 1, strlen(stringPart + 1));
              delete tempChar;
            }
            prevTemp->mNextNodes[*prevKeyIter] = newNode;
            temp = newNode;
            newNode = new Node();
            newNode->mValue = value;
            if(*(keyIter + 1) != '\0'){
              strncpy(newNode->mStringPart, keyIter + 1, strlen(keyIter + 1));
            }
            temp->mNextNodes[*keyIter] = newNode;
          } else {//Go around for another loop
            prevKeyIter = keyIter;
            keyIter++;
            stringPart++;
          }
        }
      }
    } else {
      if(*keyIter == '\0'){//We found the node we were looking for
        if(temp->mValue) return false;//There is something already here; we are done
        else { //We can insert the value and be done
          temp->mValue = value;
          return true;
        }
      }
    }
    //////////////////////////////////////////////////////////////////////////
  }
  return false;
}

ConsoleWidget.hqt(我的项目设置为在扩展名为.hqt的头文件上运行QTs MOC)

#ifndef CONSOLE_WIDGET
#define CONSOLE_WIDGET

#include <QtWidgets\qwidget.h>
#include <QtWidgets\QLineEdit.h>
#include <QtWidgets\QTextEdit.h>
#include <QtWidgets\qstyleoption.h>
#include <QtWidgets\qsizegrip.h>
#include <QtWidgets\qgridlayout.h>
#include <QtWidgets\qscrollbar.h>
#include <QtGui\qpainter.h>
//#include <QtCore\qhash.h>
#include <RadixTree.h>
//#include <Intermediary.hqt>

/*
Necessary to get around issues with static functions emiting signals.
*/
class Intermediary: public QObject{
  Q_OBJECT
public:
  void emitMessage(QString message){ emit displayUpdated(message); };
signals:
  void displayUpdated(QString message);
};

class ConsoleWidget:public QWidget{
  Q_OBJECT

  enum CommandFlag{
    None,
    ArgumentsHelp,
    DetailedHelp
  };

  enum MessageType{
    Normal,
    UserInput,
    Error
  };

  class FunctionWrapper{
  public:
    FunctionWrapper(void(*function)(QStringList, ConsoleWidget::CommandFlag)){ mFunction = function; }
    void(*mFunction)(QStringList, ConsoleWidget::CommandFlag);
  };

public:
  ConsoleWidget();
  void setParent(QWidget *parent);
  void runCommand(QString commandString, MessageType type);
  static void addCommand(QString command, void(*commandFunction)(QStringList, CommandFlag));
  static void addMessage(QString message, MessageType type);
protected:
  void paintEvent(QPaintEvent* event);
private:
  QLineEdit* mInputWidget;
  QSizeGrip* mResizeGrip;
  QTextEdit* mConsoleDisplay;
  static Intermediary mIntermediary;
  static QString mConsoleHistory;
  static RadixTree<FunctionWrapper> mCommands;
  static void helpCommand(QStringList commandElements, CommandFlag flag);
private slots:
  void userCommand();
  void updateConsoleDisplay(QString message);
};

#endif

ConsoleWidget.cpp

#include <ConsoleWidget.hqt>

//TODO help functionality
//previously typed commands

Intermediary ConsoleWidget::mIntermediary;
QString ConsoleWidget::mConsoleHistory;
//RadixTree<struct FunctionWrapper> ConsoleWidget::mCommands;

ConsoleWidget::ConsoleWidget(){
  connect(&mIntermediary, SIGNAL(displayUpdated(QString)), this, SLOT(updateConsoleDisplay(QString)));

  mInputWidget = new QLineEdit("", this);
  connect(mInputWidget, SIGNAL(returnPressed()), this, SLOT(userCommand()));

  mConsoleDisplay = new QTextEdit("", this);
  mConsoleDisplay->setHtml(mConsoleHistory);
  mConsoleDisplay->setReadOnly(true);

  mResizeGrip = new QSizeGrip(0);

  if(!mCommands.Contains("help")) mCommands.Insert("help", new FunctionWrapper(helpCommand));

  QWidget* verticalDivider = new QWidget(this);
  verticalDivider->setFixedWidth(1);
  verticalDivider->setStyleSheet("background-color: rgb(82, 82, 82);");
  QWidget* horizontalDivider = new QWidget(this);
  horizontalDivider->setFixedHeight(1);
  horizontalDivider->setStyleSheet("background-color: rgb(82, 82, 82);");
  QWidget* spacer = new QWidget(this);
  spacer->setFixedWidth(4);
  spacer->setStyleSheet("background-color: rgba(0, 0, 0, 0);");

  QGridLayout* consoleLayout = new QGridLayout();
  consoleLayout->setMargin(0);
  consoleLayout->setSpacing(0);
  consoleLayout->addWidget(mConsoleDisplay, 0, 0, 1, 3);
  consoleLayout->addWidget(spacer, 0, 3, 1, 1);
  consoleLayout->addWidget(horizontalDivider, 1, 0, 1, 4);
  consoleLayout->addWidget(mInputWidget, 2, 0, 1, 1);
  consoleLayout->addWidget(verticalDivider, 2, 1, 1, 1);
  consoleLayout->addWidget(mResizeGrip, 2, 2, 1, 2);
  setLayout(consoleLayout);
}

void ConsoleWidget::addCommand(QString command, void(*commandFunction)(QStringList, CommandFlag)){
  command = command.toLower();
  if(mCommands.Contains(command.toUtf8().data())){
    addMessage("\"" + command + "\" can not be added to ConsoleWidget because it's already here!", Error);
    return;
  }

  mCommands.Insert(command.toUtf8().data(), new FunctionWrapper(commandFunction));
}

void ConsoleWidget::addMessage(QString message, MessageType type){
  switch(type){
    case Normal:
      mConsoleHistory.append(message);
      emit mIntermediary.emitMessage(message);
      break;
    case UserInput:
      mConsoleHistory.append("<font color=#ffffff>" + message + "</font><br>");
      emit mIntermediary.emitMessage("<font color=#ffffff>" + message + "</font><br>");
      break;
    case Error: 
      mConsoleHistory.append("<font color=#e60000>Error: " + message + "</font><br>");
      emit mIntermediary.emitMessage("<font color=#E60000>Error: " + message + "</font><br>");
      break;
  }
}

void ConsoleWidget::runCommand(QString commandString, MessageType type){
  QStringList elements = commandString.toLower().split(QRegularExpression("\\s+"), QString::SkipEmptyParts);
  if(elements.size() <1) return;
  addMessage(commandString.toLower(), type);
  if(!mCommands.Contains(elements[0].toUtf8().data())){
    addMessage("\"" + elements[0] + "\" is not a valid command", Error);
    return;
  }
  mCommands.Contains(elements[0].toUtf8().data())->mFunction(elements, None);
}

void ConsoleWidget::userCommand(){
  QString command = mInputWidget->text();
  mInputWidget->setText("");
  runCommand(command, UserInput);
}

void ConsoleWidget::updateConsoleDisplay(QString message){
  mConsoleDisplay->insertHtml(message);
  mConsoleDisplay->verticalScrollBar()->setValue(mConsoleDisplay->verticalScrollBar()->maximum());
}

/*
Reimplemented to allow QSizeGrip to set it's parent
*/
void ConsoleWidget::setParent(QWidget *parent){
  mResizeGrip->setParent(parent);
  QWidget::setParent(parent);
}

/*
Paint event needs to be reimplemented in order to support QStyleSheet
*/
void ConsoleWidget::paintEvent(QPaintEvent *)
{
  QStyleOption opt;
  opt.init(this);
  QPainter p(this);
  style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

void ConsoleWidget::helpCommand(QStringList commandElements, ConsoleWidget::CommandFlag flag){

}

0 个答案:

没有答案