C++ 编译时基类构造函数的多个定义错误

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:

我正在编写一个由列向量和单元格向量组成的电子表格,其中 每个单元格都是单元格值的占位符。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

您已经正确理解了模板需要在其头文件中定义。但是类
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