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() {}
Related
I think I need some tutoring on templates, especially in conjunction with inheritance. I am well aware those two concepts don't play very well together.
We've wanted to get ride of clang tidy warnings, but I have no clue how to achieve it.
The abstracted code is below, please see https://godbolt.org/z/sPfx7Yhad to compile it.
The setting is, we have some abstract base class (Animal), and a specialized type (Dog).
A converter functionality can only be defined on the base class.
There is a templated reader class, which is templated with the actual specialized typed (Reader<Dog>).
However, clang-tidy complains when analyzing reader.h, as converter::convert is not known.
It's only known in main.cpp, by including converter.h before reader.h.
I have tried to forward declare the function by using template:
namespace converter
{
template<typename T>
void convert(const std::string& input, T& animal);
}
Which leads to linker errors, because now the linker is looking for a void convert(const std::string&, Dog&) implemenation, rather than using the void convert(cons std::string&, Animal&) overload. (see https://godbolt.org/z/x4cPfh6P4)
What can I do? How could I change the design to avoid the clang-tidy warning?
In general, I cannot add the actual includes to converter.h in reader.h, as that part is generic and the user shall be able to use the reader with their own types, by providing a custom converter functionality.
What I cannot change are classes Dog and Animal. They are autogenerated classes / libraries which we are using.
For anyone who is interested, the real world example can be found here https://github.com/continental/ecal/blob/master/samples/cpp/measurement/measurement_read/src/measurement_read.cpp
#include <string>
#include <iostream>
// animal.h
// class hierarchy with abstract base class
class Animal
{
public:
std::string name;
virtual std::string what() = 0;
};
// dog.h
class Dog : public Animal
{
public:
std::string what() override {return "dog";}
};
// animal_converter.h
// converting function
// #include <animal.h>
namespace converter
{
void convert(const std::string& input, Animal& animal)
{
animal.name = input;
}
}
// reader.h
// Templated class for reader functionality
template <typename T>
class Reader
{
public:
T read()
{
T output;
converter::convert("Anton", output);
return output;
}
};
// main.cpp
// #include dog.h
// #include animal_converter.h
// #include reader.h
int main()
{
Reader<Dog> reader;
std::cout << reader.read().name << std::endl;
}
Pretty new to C++, I was given an assignment that is basically about utilizing two different classes, however when creating my header files and c++ files and attempting to compile I get an error that reads no matching function for call to 'Owner::Owner()'. Since I am not super familiar with C++ yet I am assuming that this issue has something to do with my constructors and the way I am trying to call them, my assignment details what I think my issue is about but I am having trouble understanding exactly what needs to be done. I will provide the assignment details on the issue, as well as the code and compilation error below. Sorry for all the information I've just been stuck with this issue for a while and I can't seem to figure out a solution.
Transcribed Error
In constructor 'Dog::Dog(std::__cxx11::string, int)':
Dog.cpp:23:46: error: no matching function for call to 'Owner::Owner()' Dog::Dog(std::string unsetBreed, int unsetAge){
Assignment Details
Now you will write a program that consists of two classes, a Dog class and an Owner class. Their specification is shown in the UML diagram below. Notice that in our design, every Dog has an Owner class member. Class Owner is immutable, as mentioned above. An immutable class is just a class whose members cannot be changed(mutated) after an object was instantiated. Therefore, the Owner class does not have any setter methods. The Owner’s class attributes must be set at the time of creation(in the Owner’s constructor). You will call Owner’s constructor from inside Dog’s constructor. Do not forget to do it inside each constructor in class Dog.
Dog.h File
#ifndef DOG_H_INCLUDED
#define DOG_H_INCLUDED
#include <iostream>
#include "Owner.h"
class Dog {
//-----------------------//
private:
std::string breed;
int age;
Owner owner;
static int dogCount;
//-----------------------//
public:
Dog();
Dog(std::string, int);
std::string getBreed();
int getAge();
void setBreed(std::string);
void setAge(int);
void printDogInfo();
int getDogCount();
};
#endif // DOG_H_INCLUDED
Owner.h File
#ifndef OWNER_H_INCLUDED
#define OWNER_H_INCLUDED
#include <iostream>
class Owner {
//-----------------------//
private:
std::string name;
int age;
//-----------------------//
public:
Owner(std::string, int);
std::string getName();
int getAge();
//-----------------------//
};
#endif // OWNER_H_INCLUDED
Dog.cpp File
#include <iostream>
#include "Owner.cpp"
#include "Owner.h"
#include "Dog.h"
//---------------SETTERS------------------//
void Dog::setBreed(std::string dogBreed){dogBreed = breed;}
void Dog::setAge(int dogAge){dogAge = age;}
//--------------GETTERS------------------//
std::string Dog::getBreed(){return breed;}
int Dog::getAge(){return age;}
int Dog::getDogCount(){return dogCount;}
//--------------OTHERS-------------------//
Dog::Dog(std::string unsetBreed, int unsetAge){
Owner::Owner(std::string unsetName, int unsetOwnerAge);
Dog::setBreed(unsetBreed);
Dog::setAge(unsetAge);
}
void Dog::printDogInfo(){
Dog::getBreed();
Dog::getAge();
}
Owner.cpp File
#include <iostream>
#include "Owner.h"
#include "Dog.h"
//--------------GETTERS------------------//
int Owner::getAge(){return age;}
std::string Owner::getName(){return name;}
//--------------OTHERS-------------------//
Owner::Owner(std::string unsetName, int unsetOwnerAge){
Owner::getName();
Owner::getAge();
}
The problem here is that you don't have a constructor that receives 0 parameters.
You have 2 options:
1 - Define other constructor:
//header file
class Owner {
...
public:
Owner(std::string, int);
Owner();
...
};
//cpp file
...
Owner::Owner(){
name = "Jhon Doe";
age = 18;
}
...
2 - Define default params:
//header file
class Owner {
...
public:
Owner(std::string unsetName = "John Doe", int unsetAge = 18);
...
};
//cpp file
...
Owner::Owner(std::string unsetName = "John Doe", int unsetAge = 18);
Owner::getName();
Owner::getAge();
}
...
Note: I don't know why you are calling getter in the constructors.
Looks like your Owner class dosen't have a default constructor try including Owner::Owner() constructor.
I am learning c++ and confused about the ways to include another class in current class. For example, I am wondering whether class QuackBehavior equals to #include <QuackBehavior.h>. If they are equal, what are the differences between these two ways? The code is :
#include <string>
class QuackBehavior;
class Duck {
public:
Duck();
virtual ~Duck() {};
virtual void performQuack();
virtual std::string getDescription() = 0;
std::string getName() {return m_name;}
void setName(std::string name ) {m_name = name;}
void setQuackBehavior(QuackBehavior * behavior);
protected:
std::string m_name;
QuackBehavior * m_quackBehavior;
};
Thank you so much.
The two are not equal:
class QuackBehavior; is considered a forward-declaration, and simply informs the compiler that there is a class called QuackBehavior. This can only be used if you are using QuackBehavior as a pointer or reference:
class B;
struct C;
struct A
{
shared_ptr<B> getB() const { return b; }
const C& getC() const;
private:
shared_ptr<B> b;
};
Here the compiler doesn't need to know any implementation details of C and B, only that they exist. Notice that it's important to tell the compiler whether it's a class or struct also.
#include <QuackBehavior> is an include, and essentially copies+pastes the entire file into your file. This allows the compiler and linker to see everything about QuackBehavior. Doing this is slower, as you'll then include everything that QuackBehavior includes, and everything those files include. This can increase compile times dramatically.
Both are different, and both have their places:
Use forward-declaration when you don't need to know the implementation details of a class just yet, only that they exist (e.g. use in pointers and references)
Include the file if you are declaring an object, or you need to use functions or members of a class.
In QuackBehavior.h file, forwarding declaring QuackBehavior class will suffice.
#include <string>
class QuackBehavior; // tells the compiler that a class called QuackBehavior exists without any further elaborations
class Duck {
public:
Duck();
virtual ~Duck() {};
virtual void performQuack();
virtual std::string getDescription() = 0;
std::string getName() {return m_name;}
void setName(std::string name ) {m_name = name;}
void setQuackBehavior(QuackBehavior * behavior);
protected:
std::string m_name;
QuackBehavior * m_quackBehavior;
};
However in QuackBehavior.cpp file, you have to use #include"QuackBehavior.h" so that the compiler can find the implementation member functions
#include <QuackBehavior.h>
#include <string>
duck::duck()
{
}
Could anyone, please, explain what can cause this error?
Error: Invalid base class
I've got two classes where one of them is derived from second:
#if !defined(_CGROUND_H)
#define _CGROUND_H
#include "stdafx.h"
#include "CGameObject.h"
class CGround : public CGameObject // CGameObject is said to be "invalid base class"
{
private:
bool m_bBlocked;
bool m_bFluid;
bool m_bWalkable;
public:
bool draw();
CGround();
CGround(int id, std::string name, std::string description, std::string graphics[], bool bBlocked, bool bFluid, bool bWalkable);
~CGround(void);
};
#endif //_CGROUND_H
And CGameObject looks like this:
#if !defined(_CGAMEOBJECT_H)
#define _CGAMEOBJECT_H
#include "stdafx.h"
class CGameObject
{
protected:
int m_id;
std::string m_name;
std::string m_description;
std::string m_graphics[];
public:
virtual bool draw();
CGameObject() {}
CGameObject(int id, std::string name, std::string description, std::string graphics) {}
virtual ~CGameObject(void);
};
#endif //_CGAMEOBJECT_H
I tried cleaning my project but in vain.
It is not valid to define an array (std::string m_graphics[]) without specifying its size as member of a class. C++ needs to know the size of a class instance in advance, and this is why you cannot inherit from it as C++ won't know at runtime where in the memory the members of the inheriting class will be available.
You can either fix the size of the array in the class definition or use a pointer and allocate it on the heap or use a vector<string> instead of the array.
When I try the two forms of constructor in classes of derivation hierarchy, the result turns out to be different. Could anybody tell me why? Below are the test code.
//Person.h
#ifndef PERSON_H_
#define PERSON_H_
#include<string>
using std::string;
class Person{
private:
string firstname;
string lastname;
public:
Person(const char *fn="NoName", const char *ln="NoName"); //A
Person(const string &fn, const string &ln);
virtual ~Person(){}
};
class Gunslinger:virtual public Person{
private:
int notchnum;
public:
Gunslinger(const char*f="unknown",const char*n="unknown",int not=0);//B
virtual ~Gunslinger(){}
};
class PokerPlayer:virtual public Person{
public:
PokerPlayer(const char*fn="unknown", const char*ln="unknown");//C;
virtual ~PokerPlayer(){}
};
class BadDude:public Gunslinger,public PokerPlayer{
public:
BadDude(const char*fn="unknown", const char*ln="unknown", int notc=0);//D
};
#endif
//PersonDefinition.cpp
#include"Person.h"
#include<iostream>
#include<cstdlib>
using std::cout;
using std::endl;
using std::cin;
Person::Person(const char*fn, const char*ln):firstname(fn),lastname(ln){
}
Person::Person(const string &fn,const string &ln):firstname(fn),lastname(ln){
}
Gunslinger::Gunslinger(const char*fn,const char*ln, int not):Person(fn,ln),notchnum(not){
}
PokerPlayer::PokerPlayer(const char*fn,const char*ln):Person(fn,ln){
}
BadDude::BadDude(const char*fn, const char*ln, int notc):Person(fn,ln),PokerPlayer(fn, ln),Gunslinger(fn,ln,notc){
}
//PersonTest.cpp
#include<iostream>
#include "Person.h"
int main(){
Person a("Jack","Husain");
PokerPlayer b("Johnson","William",8);
Gunslinger c("Mensly","Sim");
}
So, here is the problem. The program above fails to compile with the default constructor with default value for all argument and throws an error message saying that "expected ',' or '...' before '!' token", but if I replace the default constructor in Line A,B,C,D with the form without argument, the program compiles and run successfully.Could anyone tell me why? Below is the error message.
You did not implement all the constructors. For instance, you declared a constructor PokerPlayer::PokerPlayer(char*, char*) but you are trying to create a PokerPlayer with PokerPlayer b("Johnson","William",8); (i.e. you never declared a constructor which takes the third argument). The declaration you want for that previous line to work is PokerPlayer::PokerPlayer(char*, char*, int);
Furthermore, you have the exact opposite problem when trying to declare a GunSlinger. Your GunSlinger class requires the third parameter and you are trying to declare it without that argument.
Even though your base class supports several types of constructors, each derived class must also have every constructor you wish to use on it explicitly declared/implemented (with the exception of the default constructor).
EDIT
Here is some semi-functional code:
class PokerPlayer : public Person
{
...
PokerPlayer(char* fname, char* lname, int val);
...
};
Implementation
PokerPlayer::PokerPlayer(char* fname, char* lname, int val) : Person(fname, lname, val)
{
// Anything else we should do...
}