Is it possible to access a class member in a global function? - c++

Though I'm sure this is a common issue, I haven't been able to find a thread on this. The closest I found was here, but it didn't ultimately seem to be asking the same thing.
I'm fairly new to C++, so I may just be doing something dumb.
Say I have the following Person class setup (Sorry for all of the code. I'm not sure exactly where the problem is--if this is even possible--so I'm including everything.):
person.h
#ifndef PERSON_H
#define PERSON_H
#include <string>
using std::string;
class Person {
public:
Person();
Person(string name);
~Person();
string name;
private:
};
#endif
person.cpp
#include "person.h"
Person::Person() {
}
Person::Person(string name) {
this->name = name;
}
Person::~Person() {
}
Then I want a global function that will change the name property of a given person:
globals.h
#ifndef GLOBALS_H
#define GLOBALS_H
#include <string>
using std::string;
class Person; // forward declaring
void changeName(Person* person, string name);
#endif
globals.cpp
#include "globals.h"
void changeName(Person* &person, string name) {
person->name = name;
}
When I try to compile I get "incomplete class" and "forward declaration" errors (I can provide if necessary). Am I doing something wrong, or would I have to do this using a class member function (e.g. Person::changeName(.....))?
Thank you for the help.

Your globals.cpp file lacks the necessary #include "person.h".
There are some other problems, too:
void changeName(Person* person, string name);
This should probably be:
void changeName(Person& person, string name);
Unless you want to make it possible to call the function with nullptr.
void changeName(Person* &person, string name) {
person->name = name;
}
Should be:
void changeName(Person& person, string name) {
person.name = name;
}
Then there's this:
Person::Person(string name) {
this->name = name;
}
You should use an initialisation list instead:
Person::Person(string name) : name(name) {}
And I'm not sure if you are aware of the possibility of passing std::string via const&. It used to be the guideline for passing strings, until C++11 came along and created ongoing discussions about best practices for passing big objects.

For a start the following:
Person(string name);
should be
Person(const string& name);
For performance
And string name should be in the private bit,
Also then signature for
void changeName(Person* person, string name);
in the header differs from the code in the .cpp file
i.e.
void changeName(Person* &person, string name) {
Also put in the #include as stated by the other person

Related

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() {}

Why am I getting a "no matching function" error?

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.

Cannot create multiple instances of a class?

My problem is that i want to create multiple instances of my upgrade class, for different upgrades. Maybe it's because i'm used to java but i can't just type Source first("first"), second("second"); because if i do and call first.getName() for example, i get "second". I made an example file where i only wrote what i'm struggling with, so you don't have to try to understand my mess of a code.
Source.cpp: I want multiple instances of this class.
#include "Source.h"
std::string name;
Source::Source()
{
}
Source::Source(std::string nameToSet)
{
name = nameToSet;
}
std::string Source::getName()
{
return name;
Source.h
#pragma once
#include <string>
class Source {
public:
Source();
Source(std::string namel);
std::string getName();
};
Test.cpp
#include "Source.h"
#include "iostream"
Source first("first"), second("second");
int main()
{
std::cout << first.getName() << std::endl;
}
Output: second
Test.h
#pragma once
#include <string>
The problem is with this line:
std::string name;
This declares a single global string named name. This variable is not associated with any Source instance. Instead, you need to declare a field inside the Source class:
class Source {
public:
Source();
Source(std::string namel);
std::string getName();
// Add these two lines
private:
std::string name;
};
This will give a name for each Source. I suggest you study about class fields and the differences between public and private access.
add std::string name in your header file like that:
#pragma once
#include <string>
class Source {
private:
std::string name;
public:
Source();
Source(std::string namel);
std::string getName();
};
by this, everytime you call the constructor, "name" will be initiated to a single value that refers to your specific instance (first, second, etc).

forward declaration on c++ with a list inside

I have two clases Pet and Person
Here is the Person.h:
#ifndef PERSON_H
#define PERSON_H
#include <list>
class Pet;
class Person
{
public:
Person();
Person(const char* name);
Person(const Person& orig);
virtual ~Person();
bool adopt(Pet& newPet);
void feedPets();
private:
char* name_;
std::list<Pet> pets_;
};
#endif
And here is the Pet.h
#ifndef PET_H
#define PET_H
#include <list>
#include "Animal.h"
class Person;
class Pet : public Animal
{
public:
Pet();
Pet(const Pet& orig);
virtual ~Pet();
std::list<Pet> multiply(Pet& pet);
private:
std::string name_;
Person* owner_;
};
#endif
The problem that i have is this:
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/list.tcc:129: error: invalid use of undefined type `struct Pet'
Person.h:13: error: forward declaration of `struct Pet'
I fixed trying to put this std::list<Pet>* pets_; but when i tried to call list functions always have a link problem. My question is how a have to include a list inside a class that contains objects from another class.
The standard requires that, except where explicitly stated, you use complete types with the library templates. This basically inhibits your design (where each object maintains by value a list of the other type).
You can work around this by using [smart] pointers (either a pointer to the container or container of pointers).

C++ Inheritance - Running Parent Method in Child Class

My parent class, Course, has the method addStudent(Student s). My child class, BetterCourse, inherits from Course. Every time I try to run BetterCourse.addStudent(s), I get the following error:
error: no matching function for call to
‘BetterCourse::addStudent(Student (&)())’ note: candidates are: void Course::addStudent(Student)
I understand it's telling me addStudent() hasn't been defined in BetterCourse and that it's recommending I use the one present in the parent class, Course. This has me confused as the whole idea around inheritance is not needing to redefine inherited functions and variables.
Course is as follows:
#include <iostream>
#include <string>
#include "Student.h"
using namespace std;
class Course
{
protected:
string id;
string name;
public:
Course();
Course(string id, string name);
void addStudent(Student s);
};
Course::Course()
{
//code
}
Course::Course(string id, string name)
{
//code
}
void Course::addStudent(Student s)
{
//code
}
BetterCourse:
#include <iostream>
#include <string>
#include "Course.h"
using namespace std;
class BetterCourse : public Course
{
public:
BetterCourse(string id, string name) : Course(id,name){};
};
From your error it seems that you for the first time get to the ugliest part of C++.
This:
Student s();
Is function declaration - not object definition. s type is Student (*)() so when you call:
BetterCourse bc;
bc.addStudent(s);
You get your error - you don't have method to add functions returning Student.
Define Student in the following ways:
Student s;
Student s {}; // new C++11 way
Student s = Student(); //
It sounds like you're actually calling the function 'addStudent' with an inappropriate argument. Could you show the code that is actually calling addStudent on the BetterCourse object? It sounds like you're using a reference to the student instead of the student object itself.
you can not call BetterCourse.addStudent(s) you should create an object
BetterCourse obj;
obj.addStudent(s);
should work
If you want to call BetterCourse::addStudent(s) than declare addStudent(s) as static method