C++ 编译时基类构造函数的多个定义错误
我正在编写一个由列向量和单元格向量组成的电子表格,其中 每个单元格都是单元格值的占位符。CellValueBase是基类,CellValue是最终的模板类 这就是错误:C++ 编译时基类构造函数的多个定义错误,c++,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:
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
您已经正确理解了模板需要在其头文件中定义。但是类
CellValueBase
不是模板,因此头文件中CellValueBase
构造函数的定义不正确。这意味着构造函数将在包含头文件的任何地方定义
简单的解决方案?在类中内联定义CellValueBase
构造函数(就像您已经使用析构函数一样)
此外,类中所有虚拟但非抽象的函数都必须有一个定义。因此,要么将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:
};
类CellValueBase
{
公众:
CellValueBase(){}/查看CellValueBase.h。不能在头文件中定义类之外的非内联类方法。必须在.cpp文件中定义它们。
将此方法的定义移动到CellValueBase.cpp:
CellValueBase::CellValueBase()
{
} // CellValueBase
在头文件中定义非内联方法或函数是完全错误的做法。错误不会立即出现,只有当您将此头文件包含在两个cpp文件中时才会出现。这意味着链接器会找到两个相同的方法定义,这就是问题所在。如果您将定义保留在头文件CellValueBase.h中,并将CellValueBase.h包含在.cp中一次但当您多次包含CellValueBase.h时,链接器就会发现重复的定义
但即使您知道不会多次包含带有非内联方法定义的头文件,您也应该记住永远不要在类之外定义非内联函数或类方法。您可以忘记此文件的“1包含规则”,稍后再包含两次,链接器将检测到重复的定义。
您还可以定义没有专门化的模板方法,或者在头文件中定义内联专门化的模板方法。我忘了提到我已经尝试将CellValueBase和CellValue的成员函数放在一个单独的.cc文件中,这给了我同样的错误。CellValueBase::CellValueBase(){}
不应出现在头文件中。请更改为内联函数或移动到cpp文件。对于将来的问题,请学习如何创建。列。h
似乎缺失,包括所有其他头的防护装置谢谢您的回答!我定义了CellValueBase构造函数和returnValueNumber内联函数.但是,构造函数仍然是多定义的;C@user3889966您记得要删除构造函数的旧的非内联定义吗?是的,我删除了该函数!所有非内联函数都是CellValue中的memberfunctions。@user3889966,并且所有对象文件都已重建?您似乎没有列出作为目标的所有头文件(间接)取决于makefile中的。请更新依赖项以使其完整,或删除所有对象文件并重新生成。我删除了对象文件并重试,但这一次模板类成员函数returnValueNumber是乘法定义的。
#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
#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
#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;
};
#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
#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;
}
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
class CellValueBase
{
public:
CellValueBase() {} // <- Define inline
virtual ~CellValueBase() {};
//virtual std::string returnValueStringEdit() = 0;
virtual float returnValueNumber() = 0; // <- Declare abstract
void emptyCell();
private:
};
CellValueBase::CellValueBase()
{
} // CellValueBase