我正在编写一个由列向量和单元格向量构成的电子表格,其中 每个单元格都是单元格值的占位符。 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
答案 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;对于此文件,稍后将其包含两次,链接器将检测重复的定义。 您也可以在没有专门化的情况下定义模板方法,也可以在头文件中定义内联专用模板方法。