编译

时间:2018-04-17 13:26:12

标签: c++

我正在编写一个由列向量和单元格向量构成的电子表格,其中 每个单元格都是单元格值的占位符。 CellValueBase是基类,CellValue是最终的模板类。

这是错误:

g++ Cell.o Column.o sheet.o main.o -o spreadsheet
sheet.o: In function `CellValueBase::CellValueBase()':
sheet.cc:(.text+0x0): multiple definition of `CellValueBase::CellValueBase()'
Column.o:Column.cc:(.text+0x0): first defined here
sheet.o: In function `CellValueBase::CellValueBase()':
sheet.cc:(.text+0x0): multiple definition of `CellValueBase::CellValueBase()'
Column.o:Column.cc:(.text+0x0): first defined here
main.o: In function `CellValueBase::CellValueBase()':
main.cc:(.text+0x0): multiple definition of `CellValueBase::CellValueBase()'
Column.o:Column.cc:(.text+0x0): first defined here
main.o: In function `CellValueBase::CellValueBase()':
main.cc:(.text+0x0): multiple definition of `CellValueBase::CellValueBase()'
Column.o:Column.cc:(.text+0x0): first defined here
Cell.o: In function `CellValueBase::~CellValueBase()':
Cell.cc:(.text._ZN13CellValueBaseD2Ev[_ZN13CellValueBaseD5Ev]+0xd): undefined reference to `vtable for CellValueBase'
Cell.o: In function `CellValueBase::CellValueBase()':
Cell.cc:(.text._ZN13CellValueBaseC2Ev[_ZN13CellValueBaseC5Ev]+0x9): undefined reference to `vtable for CellValueBase'
Cell.o:(.rodata._ZTI9CellValueIfE[_ZTI9CellValueIfE]+0x10): undefined reference to `typeinfo for CellValueBase'
Column.o: In function `CellValueBase::CellValueBase()':
Column.cc:(.text+0x9): undefined reference to `vtable for CellValueBase'
sheet.o: In function `CellValueBase::CellValueBase()':
sheet.cc:(.text+0x9): undefined reference to `vtable for CellValueBase'
main.o: In function `CellValueBase::CellValueBase()':
main.cc:(.text+0x9): undefined reference to `vtable for CellValueBase'
collect2: error: ld returned 1 exit status
Makefile:8: recipe for target 'Spreadsheet' failed
make: *** [Spreadsheet] Error 1

这是我的代码:

main.cc

#include <iostream>
#include "sheet.h"

using namespace std;

int main () {
   Sheet *sht;

   sht = new Sheet ();

   return 0;
}//main

sheet.h

#ifndef SHEET_H
#define SHEET_H

#include "Column.h"

// Vaste grootte van de sheet
const int AantReg = 24;
const int AantKol = 80;

class Sheet
{
    public:
      Sheet ();
      void getCell();

      void begin();
      void end();

    private:
      std::vector<Column*> sheetCol;//bevat de columns
      int regels, kolommen;

};

#endif

sheet.cc

#include <iostream>
#include "sheet.h"

using namespace std;

Sheet::Sheet () {
   regels = AantReg;
   kolommen = AantKol;

   cout << "Kolommen" << endl;
   for (int i = 0; i < kolommen; i++) {
      cout << "kolomnr: " << i << endl;
      sheetCol.push_back(new Column(regels));
   }
   cout << endl << endl;
}

void Sheet::getCell () {
   //TODO: fixen
}

void Sheet::begin () {
   //TODO: deze shit ook fixen
}

void Sheet::end () {

}

Column.h

#include <vector>
#include "Cell.h"
class Column
{
    public:
      Column (int n);
      //void getCell();
      //void begin();
      //void end();

    private:
      int aantCellen;
      std::vector<Cell*> columnVec;//sla je de cellen in op

};

#endif

Column.cc

#include <iostream>
#include "Column.h"

using namespace std;

Column::Column(int n): aantCellen(n)
{
    for (int i = 0; i < aantCellen; i++) {
        cout << "celnr: " << i << endl;
        columnVec.push_back(new Cell());
    }

}//cell

Cell.h

#ifndef CELL_H
#define CELL_H

#include "CellValueBase.h"
#include <string>
#include <memory>
    class Cell {
        public:
            Cell();

            void setValueFloat(float newValue);
            //void setValueInt(int newValue);
            //void setValueString(std::string newValue);
            //void setValueFormula(std::string newValue);

            //std::unique_ptr<cellValueBase> readValue();
            void emptyCell();
        private:
            std::unique_ptr<CellValueBase> value;
    };

#ENDIF

Cell.cc

#include "Cell.h"
#include <iostream>

using namespace std;

Cell::Cell() {
   value.reset(nullptr);
   cout << "hallo wereld ik ben een cel" << endl;
   setValueFloat(3.14);
} // Cell

void Cell::setValueFloat(float newValue)
{
   value = unique_ptr<CellValueBase>(new CellValue<float>(newValue));
   value->returnValueNumber();
} // setValueFloat

CellValueBase.h

#ifndef CELLVALUEBASE_H
#define CELLVALUEBASE_H

#include <iostream>
#include <string>
#include <sstream>
#include <stdexcept>

 class CellValueBase
 {
     public:
         CellValueBase();
         virtual ~CellValueBase() {};

         //virtual std::string returnValueStringEdit() = 0;
         virtual float returnValueNumber();
         void emptyCell();
     private:
 };

CellValueBase::CellValueBase()
{

} // CellValueBase


template<typename T>
class CellValue final : public CellValueBase
{
     public:
         CellValue(T initial_value)
             : CellValueBase(), value(initial_value)
             { }
         ~CellValue();

         //std::string returnValueString();

         //std::string returnValueStringEdit();

         float returnValueNumber();

     private:
         T value;
};

template<typename T>
CellValue<T>::~CellValue()
{
   // TODO
}

template<typename T>
float CellValue<T>::returnValueNumber() {
   return value;
}

和makefile:

CC = g++

CompileParms = -c -std=c++14 -Wall -Wextra

OBJS = Cell.o Column.o sheet.o main.o

Spreadsheet: $(OBJS)
    $(CC) $(OBJS) -o spreadsheet


Cell.o: Cell.cc CellValueBase.h Cell.h
    $(CC) $(CompileParms) Cell.cc

Column.o: Column.cc Column.h
    $(CC) $(CompileParms) Column.cc

sheet.o: sheet.cc sheet.h
    $(CC) $(CompileParms) sheet.cc

main.o: main.cc sheet.h
    $(CC) $(CompileParms)  main.cc

2 个答案:

答案 0 :(得分:1)

您已正确理解需要在其头文件中定义模板。但是类CellValueBase 不是模板,因此头文件中CellValueBase构造函数的定义不正确。这意味着将在包含头文件的任何地方定义构造函数。

简单的解决方案?在类中定义CellValueBase构造函数 inline (就像你已经使用析构函数一样)。

此外,类中的所有虚拟但非抽象函数必须具有定义。所以要么使CellValueBase::returnValueNumber抽象,要么有一个空的定义。

总而言之,CellValueBase类看起来像这样:

 class CellValueBase
 {
     public:
         CellValueBase() {}  // <- Define inline
         virtual ~CellValueBase() {};

         //virtual std::string returnValueStringEdit() = 0;
         virtual float returnValueNumber() = 0; // <- Declare abstract
         void emptyCell();
     private:
 };

答案 1 :(得分:0)

查看CellValueBase.h。您不能在头文件中定义类外的非内联类方法。您必须在.cpp文件中定义它们。 将此方法的定义移至CellValueBase.cpp:

CellValueBase::CellValueBase()
{

} // CellValueBase    

在标题中定义非内联方法或函数是完全不好的做法。错误不会立即出现,只有在两个cpp文件中包含此标头时才会出现错误。这意味着链接器创建了两个相同的方法定义,这就是问题所在。如果你在头文件CellValueBase.h中留下定义并在.cpp文件中包含一次CellValueBase.h那么就不会出现任何问题。但是当您不止一次包含CellValueBase.h时,链接器会发现重复的定义。

但即使你知道你不会包含带有非内联方法定义的头文件,那么你也应该记住永远不要在类之外定义非内联函数或类方法。你可以忘记你的&#34; 1包含规则&#34;对于此文件,稍后将其包含两次,链接器将检测重复的定义。 您也可以在没有专门化的情况下定义模板方法,也可以在头文件中定义内联专用模板方法。