遵循一个定义规则,但 C++ 抛出重新定义错误

问题描述

C++ 中非常奇怪的重定义错误,尤其是包括 main 在内的所有其他文件都没有错误

我有我的头文件(各种动物)和一个实现文件“animals.cpp”。

我的标题遵循以下格式:

class Mammal : public Animal{
    public:
        Mammal(){} //empty constructor
        virtual ~Mammal(){} // destructor
        void createNewMammalObject(std::string name,std::string trackingNum,std::string nurse,std::string subType,std::string type){}
        std::string getSubtype() {}
        void setSubtype(std::string subType){}
        int getNursing(){}
        void setNursing(int nursing){}
        void setType(std::string type){}
        int getNumEggs(){}

    protected:
        int nursing;
};

实现文件中的实现如下所示:

Mammal::Mammal() {} //empty constructor

virtual Mammal::~Mammal(){} // destructor

void Mammal::createNewMammalObject(std::string name,std::string code,std::string type){
    this->setNursing(nursing);
    this->setSubType(subType);
    this->createNewAnimalObject(name,trackingNum,subType,type);
}

std::string Mammal::getSubtype() {
    return subType;
}

void Mammal::setSubtype(std::string subType) {
    this->subType = subType;
}

int Mammal::getNursing() {
    return this->nursing;
}

void Mammal::setNursing(int nursing) {
    this->nursing = nursing;
}

void Mammal::setType(std::string type){
    this->type = type;
}

int Mammal::getNumEggs() {
    return 0;
}

我的#includes 实现文件是:

#include "animal.h"
#include "oviparous.h"
#include "mammal.h"
#include "crocodile.h"
#include "goose.h"
#include "pelican.h"
#include "bat.h"
#include "seaLion.h"
#include "whale.h"

所有头文件和实现都遵循这种格式以遵循单一定义,除了animal.h,它是一个抽象类并且确实包含函数定义。所有其他函数肯定只定义一次。但是,在构建项目之后,实现文件中的每个函数都说这是一个重新定义并指向作为原始定义的头文件。我非常困惑。这是 Eclipse 的问题吗?我的抽象类是否应该像其他头文件一样在我的实现文件中定义?

解决方法

关于你的头文件(专注于one行,但他们几乎all都有同样的问题):

std::string getSubtype() {}
//                       ^^
//                    see here

这是一个带有空函数体的定义,一个非定义的声明是:

std::string getSubtype();

您在头实现文件中定义函数这一事实几乎肯定是您违反 ODR 的原因。

还有另外两点,不一定是致命的:


首先,首先设置基类是正常的,这样派生类就可以覆盖特定的属性。这将导致重新排序(在还修复了护士/护理差异之后):

#include <string>

void Mammal::createNewMammalObject(
    std::string name,std::string code,std::string subType,std::string type,std::string nursing  // moved to end,just a foible of mine.
) {
    this->createNewAnimalObject(name,trackingNum,subType,type);
    // Could now modify below any of those items in previous line.

    this->setNursing(nursing);
    this->setSubType(subType);
}

其次,构造函数通常会做尽可能多的工作,而不是让一些函数进行设置。后者可能会导致如果您忘记调用该函数,构造的对象可能处于某种奇怪的不可用状态。

我会更多地关注以下内容:

#include <string>

class Animal {
public:
    Animal(
        std::string name,std::string trackingNum,std::string type
    )
    :   m_name(name),m_trackingNum(trackingNum),m_subType(subType),m_type(type)
    {
        // Other less important initialisation and possibly also
        // throwing exception if any of those four above are invalid.
    }
private:
    std::string m_name;
    std::string m_trackingNum;
    std::string m_subType;
    std::string m_type;
};

class Mammal :Animal {
public:
    Mammal(
        std::string name,std::string nursing
    )
    :   Animal(name,type),m_nursing(nursing)
    {
        // Ditto on more initialisation and throwing
        // for bad nursing value.
    }
private:
    unsigned int m_nursing;
};

int main() {}