简体   繁体   中英

One-Definition Rule Followed, but C++ throws Redefinition Error

Very strange redefinition error in C++, especially as every other file including main is error-free.

I have my headers (various animals) and an implementation file "animals.cpp".

My headers follow the format:

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;
};

And implementation in the implementation file looks like:

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

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

void Mammal::createNewMammalObject(std::string name, std::string code,std::string nurse,std::string subType, 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;
}

My #includes for the implementation file are:

#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"

All headers and implementation follow this format to follow the One-Definition, except for animal.h which is an abstract class and does contain function definitions. All other functions are definitely only defined once. However, after building the project, EVERY function in the implementation file is saying it's a redefinition and pointing back to the headers as the original definition. I'm incredibly confused. Is this an Eclipse problem? Should my abstract class be defined in my implementation file like the other headers?

Regarding your header file (focussing on one line but they pretty much all have the same problem):

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

This is a definition of a function with an empty body, a non-definition declaration would be:

std::string getSubtype();

The fact that you're defining functions in both the header and implementation file is almost certainly the cause of your ODR violations.

And just two other points, neither necessarily fatal:


First, it's normal to set up the base class stuff first so that derived classes can override specific properties. That would result in a reordered (after also fixing the nurse/nursing discrepancy):

#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);
}

Second, it's usual for the constructor to do as much work as possible, rather than having some function set things up. The latter leads to the possibility that a constructed object may be in some weird unusable state if you forget to call that function.

I would be looking at something more along the lines of:

#include <string>

class Animal {
public:
    Animal(
        std::string name,
        std::string trackingNum,
        std::string subType,
        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 trackingNum,
        std::string subType,
        std::string type,
        std::string nursing
    )
    :   Animal(name, trackingNum, subType, type)
    ,   m_nursing(nursing)
    {
        // Ditto on more initialisation and throwing
        // for bad nursing value.
    }
private:
    unsigned int m_nursing;
};

int main() {}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM