I feel stupid right now, haven't been doing C++ in ages, can't understand what's wrong... However I got this following class:
#include <string>
class NamedObject
{
public:
NamedObject();
virtual ~NamedObject();
virtual std::string getName() const { return m_name };
virtual void setName(const std::string name) { m_name = name };
private:
std::string m_name;
};
And now I'm inheriting a simple class out of it:
#include "NamedObject.h"
enum eTeam { eAttacker, eDefender, eSpectator, eNone };
class Player : public NamedObject
{
public:
Player();
virtual ~Player();
virtual void printName();
virtual eTeam getTeam() const { return m_team };
virtual void setTeam(const eTeam team) { m_team = team };
private:
std::string m_name;
eTeam m_team;
};
However, I am unable to use player->setName("blabla") from my main.cpp? Here's the main file:
#include "Player.h"
int main()
{
Player* p1 = new Player();
p1->setName("Name Changed!")
p1->printName(); // prints "Unnamed" since I declared that in default ctor
return 0;
}
I'm not getting any errors, everything runs up well, the name just doesn't simply change. Also, I got all of the constructors and destructors, as well as my printName-method working perfectly, and the problem is not within them.
What you see is that setName modifies the m_name in the parent class and printName prints out the m_name of the derived class because you're redeclaring std::string m_name; in the derived class.
Remove the declaration from the derived class and mark m_name as protected member in the parent class:
#include <string>
class NamedObject
{
public:
NamedObject();
virtual ~NamedObject();
virtual std::string getName() const { return m_name };
virtual void setName(const std::string name) { m_name = name };
protected:
std::string m_name;
};
You could also keep m_name private and use the method getName() instead, as suggested by moswald.
You created another different variable m_name in your derived class that shadowed the one in the parent class.
I can see that must not be your real code.
Your derived/super class is redeclaring m_name. Probably not what you mean to do;)
Related
I have declared a class Products and another class CD the class CD is inheriting the class Products.
Now I have declared an constructor to update the value of the. and I am getting an error
#include <iostream>
#include <string>
class Products
{
private:
std::string name;
std::string type;
double price;
public:
virtual std::string getname();
virtual double getprice();
virtual void show();
std::string gettype()
{
return type;
}
};
class CD: public Products
{
private:
std::string artist;
std::string studio;
public:
CD(std::string sname,double sprice,std::string sartist,std::string sstudio)
{
this->type = "CD";
this->name = sname ;
this->price = sprice;
this->artist = sartist;
this->studio = sstudio;
}
void show()
{
std::cout<<"\nName of the CD:\t"<<this->name;
std::cout<<"\nArtist of the CD:\t"<<this->artist;
std::cout<<"\nStudio of the CD:\t"<<this->studio;
std::cout<<"\nPrice of the cd:\t"<<this->price;
}
};
int main()
{
CD obj("Oceans",49,"somesinger","somestudio");
}
ERROR :
In constructor 'CD::CD(std::string, double, std::string)';
'std::string Products::type' is private within this context
this->type="CD";
'std::string Products::name' is private within this context
this->name=sname;
'double Products::price' is private within this context
this->price= sprice;
Basically it is not giving error for the private data members of the CD class but just the data members that are being inherited from Products Class
#include <iostream>
#include <string>
class Products
{
private:
std::string m_name;
std::string m_type;
double m_price;
public:
// No need for your setters/getters to be virtual
// if the derived class won't override anything or not
const std::string& getType() const { return m_type; }
const std::string& getName() const { return m_name; }
double getPrice() const { return m_price; }
void setType(const std::string& new_type) { m_type = new_type; }
void setName(const std::string& new_name) { m_name = new_name; }
void setPrice(double new_price) { m_price = new_price; }
// Force derived class to override function
virtual void show() = 0;
};
class CD: public Products
{
private:
std::string artist;
std::string studio;
public:
CD(std::string sname,double sprice,std::string sartist,std::string sstudio)
{
this->setType("CD");
this->setName(sname) ;
this->setPrice(sprice);
this->artist = sartist;
this->studio = sstudio;
}
void show()
{
std::cout<<"\nName of the CD:\t"<<this->getName();
std::cout<<"\nArtist of the CD:\t"<<this->artist;
std::cout<<"\nStudio of the CD:\t"<<this->studio;
std::cout<<"\nPrice of the cd:\t"<<this->getPrice();
}
};
int main()
{
CD obj("Oceans",49,"somesinger","somestudio");
obj.show();
}
I want you to understand some changes here. First the removal of virtual keyword. In your case the setters/getters had no need to be virtual, as they were not being overriden or didn't have a need to be based on the current example. Second, the setters/getters are setup to access the private members accordingly. We now use these functions within class CD. Also we changed the function show() to be pure virtual notice the = 0 at the end. I added a comment saying this forces derived classes to override the function. Lastly, your main wasn't doing anything so I added a obj.show() to actually print something.
In this solution, I've added a constructor for Products, and CD's constructor calls it to initialize the members that are private to Products.
I removed the virtual on getName and getPrice since these features don't change other products.
show remains virtual, and I split it into a piece in Products and a piece in CD so they each display their respective fields. This separates the printing according to where the variables are, so for example, another class derived from Products wouldn't have to reimplement printing of name and price.
#include <iostream>
#include <string>
class Products
{
private:
std::string name;
std::string type;
double price;
public:
std::string getname(); // Does not need to be virtual, as it's not overriden
double getprice(); // Also does not need to be virtual
virtual void show() const {
std::cout<<"\nName of the " << type << ":\t"<<this->name;
std::cout<<"\nPrice of the " << type << ":\t"<<this->price;
};
Products (const std::string &stype, double sprice, const std::string &sname)
: name (sname), type (stype), price (sprice) {
}
std::string gettype() const
{
return type;
}
};
class CD: public Products
{
private:
std::string artist;
std::string studio;
public:
CD(const std::string &sname,double sprice, const std::string &sartist, const std::string &sstudio)
: Products ("CD", sprice, sname)
{
artist = sartist;
studio = sstudio;
}
void show() const override
{
Products::show(); // Call parent show() to show the basics
std::cout<<"\nArtist of the " << gettype() << ":\t"<<this->artist;
std::cout<<"\nStudio of the " << gettype() << ":\t"<<this->studio;
}
};
int main()
{
Products shoe ("Shoe", 3.49, "Nike runner");
shoe.show();
CD obj("Oceans",49,"somesinger","somestudio");
obj.show();
}
I got an Abstract Baseclass which looks like this:
class AbstractClass {
public:
virtual ~AbstractClass() = 0 {}
std::string GetName() const { return m_Name; }
private:
std::string m_Name;
};
Now I got many derived Classes and I want to implement them like this
class DerivedClass1 : public AbstractClass{
public:
DerivedClass1() = default;
~DerivedClass1() = default;
private:
std::string m_Name = "DerivedClass1";
};
int main() {
DerivedClass1 class1;
std::cout << class1.GetName();
return 0;
}
I dont want to override GetName() everytime i derive a Class, is this possible?
Edit:
I got a Linker Error. Error LNK2019.
Use only one name, in the base class, and a constructor with a parameter:
class AbstractClass{
public:
AbstractClass(const std::string& name) : m_Name(name){}
std::string GetName() const { return m_Name; }
private:
std::string m_Name;
};
DerivedClass1 : public AbstractClass{
public:
DerivedClass() : AbstractClass("DerivedClass1") {}
};
int main(){
DerivedClass1 class1;
std::cout << class1.GetName();
return 0;
}
There seems to be no reason for making the base class abstract, but if you do need that, even a pure virtual destructor must have a definition, or you will get a linker error, because it's needed when destroying derived objects.
Also, if the destructor didn't exist, when would m_Name be destroyed?
class Abstract
{
public:
virtual ~Abstract() = 0;
};
Abstract::~Abstract() {}
This makes a class that can't be instantiated, but whose derived classes can still be destroyed.
That's not how you "override" GetName(). You can either make GetName() virtual and override it in your derived classes:
class AbstractClass {
public:
virtual ~AbstractClass() = default;
virtual std::string GetName() const { return "AbstractClass"; }
private:
std::string m_Name;
};
and:
class DerivedClass1 : public AbstractClass {
public:
DerivedClass() = default;
std::string GetName() const override { return "DerivedClass1"; }
};
Or you can set m_Name in your derived classes by passing it to the base class constructor:
class AbstractClass {
public:
AbstractClass(const std::string& name) : m_Name(name) {}
virtual ~AbstractClass() = default;
std::string GetName() const { return m_Name; }
protected: // protected not private
std::string m_Name;
};
and:
class DerivedClass1 : public AbstractClass {
public:
DerivedClass() : AbstractClass("DerivedClass1") {}
};
Or you can set it in the derived's class constructor:
class AbstractClass {
public:
virtual ~AbstractClass() = default;
std::string GetName() const { return m_Name; }
protected: // protected not private
std::string m_Name;
};
and:
class DerivedClass1 : public AbstractClass {
public:
DerivedClass() : AbstractClass() { m_Name = "DerivedClass1"; }
};
You get the link error because the destructor for AbstractClass needs to be defined even if it is empty.
AbstractClass::~AbstractClass()
{
// Compulsory virtual destructor definition,
// even if it's empty
}
LIVE on Wandbox
Regarding overriding getName: you do not have to. If you do not provide an implementation in the derived class, the one inherited one is used.
Code sugest that problem is how to get a class name? But this is not clearly stated in question (XY problem)
How to handle class name?
You can use RTTI:
class ClassName {
public:
virtual ~ClassName() {} // just to enable RTTI for all decendants
std::string getClassName() {
return typeid(*this).name();
}
};
https://wandbox.org/permlink/LvPdA37arMr0LFQW
But as you can see it adds some extra prefix (it is compiler depended). boost can clean it up:
https://wandbox.org/permlink/8XiB7yVOM0wYVxpl
I'm trying to create a class containing a virtual function, which i would like to inherit in two child classes.
I know some people already asked this (here and there for example), but i couldn't understand the answers.
So i made a simplified example code of what i'm trying :
//Mother .h file
#ifndef _MOTHER_H_
#define _MOTHER_H_
#include <iostream>
class Mother
{
protected :
std::string _name;
public:
Mother(std::string name);
~Mother();
virtual std::string getName() = 0;
};
#endif
//Mother .cpp file
#include "Mother.h"
Mother::Mother(std::string name)
{
this->_name = name;
}
Mother::~Mother()
{
}
//Child.h file
#ifndef _CHILD_H_
#define _CHILD_H_
#include "Mother.h"
class Child : public Mother
{
private :
std::string _name;
public:
Child(std::string name);
~Child();
};
#endif
//Child .cpp file
#include "Mother.h"
#include "Child.h"
Child::Child(std::string name) : Mother(name)
{
this->_name = name;
}
Child::~Child()
{
}
std::string Mother::getName()
{
return this->_name;
}
Here is my main.cpp file :
//Main.cpp file
#include "Child.h"
int main()
{
Child l("lol");
std::cout << l.getName() << std::endl;
Mother& f = l;
std::cout << f.getName() << std::endl;
return 0;
}
Here's what the compilator says :
(compiling with g++ *.cpp -W -Wall -Wextra -Werror)
main.cpp: In function ‘int main()’:
main.cpp:5:9: error: cannot declare variable ‘l’ to be of abstract type‘Child’
In file included from main.cpp:1:0:
Child.h:8:7: note: because the following virtual functions are pure within ‘Child’:
In file included from Child.h:6:0,
from main.cpp:1:
Mother.h:14:23: note: virtual std::string Mother::getName()
What am i doing wrong ?
(sorry if i made some english mistakes, i am not a native speaker).
In Mother's declaration you have:
virtual std::string getName() = 0;
This is not just a virtual, but a pure virtual. The distinction between a virtual and a pure virtual is that the pure variety must have an override implemented in a derived class, even if you have provided an implementation in the base class. For example:
class Foo
{
public:
virtual void DoIt() = 0 {}; // pure virtual. Must be overridden in the derived class even though there is an implementation here
};
class Bar : public Foo
{
public:
void DoIt(); // override of base
};
void Bar::DoIt()
{
// implementation of override
}
You can't instantiate a class with un-implemented pure virtual methods. If you try, you will get a compiler error:
int main()
{
Foo f; // ERROR
Bar b; // OK
}
And that is exactly what you tried to do. You declared getName() to be pure virtual in
Mother, but you did not override it in Child. Then you tried to instantiate a Child
int main()
{
Child l("lol");
Which resulted in the compiler error.
To fix it, provide an override of getName() in the Child class.
You class child should override getName() method as it is pure virtual defined in class mother
Seems typo to me.. as std::string Mother::getName() is defined in child.cpp..
std::string Child::getName()
{
return this->_name;
}
The pure virtual function in your base class Mother does not make sense from an OOP perspective, it is a common trait in all children so the same function could be used. There is no need to override it.
struct Person
{
Person(std::string name) : _name(name) {}
std::string _name;
std::string getName() {return _name; }
};
struct Mother : Human
{
Mother(std::string name) : Person(name) {}
};
struct Child : Human
{
Child(std::string name) : Person(name) {}
};
Title edits that reflect a better summary of the question are welcome.
I'd like to refactor these three classes somehow to remove the duplicate field represented in class C (see hierarchy). I thought about pulling the field up into a parent class, but the issue is that A and B are not similar enough to be considered "is-a", C is considered both, and it is literally only one member field so creating a class just to hold ONE THING seems a bit overkill.
Hierarchy:
(abstract data type)
class A : public O {
public:
//...
std::string GetName();
std::string GetName() const;
void SetName(std::string name);
//...
protected:
//...
std::string _name;
//...
};
//Methods and fields shown here represent the exact same representative data as in A but the classes are so dissimilar as to not be considered "is-a" relationship.
(abstract data type)
class B {
public:
//...
std::string GetName();
std::string GetName() const;
void SetName(std::string name);
//...
protected:
//...
std::string _name;
//...
};
(concrete)
class C : public A, public B {
public:
//...
C(/*..Other parameters..*/, std::string name, /*....*/)
: A(name, /*...*/), B(name, /*...*/) {
/*...*/
}
//...
private:
//...
};
You can either leave it as-is, as said previously or you can consider using composition over inheritance for class C like:
class C : public A
{
public:
// ...
// The GetName and SetName methods are inherited from A.
private:
B* b;
};
or
class C
{
public:
// ...
std::string GetName();
std::string GetName() const;
void SetName(std::string name);
private:
A* a;
B* b;
};
Looking at this question and answers: Get rid of ugly if statements clearly shows that, as #Andre mentioned, your current code is perfectly acceptable and trying to "fix" it may cause same pain and mind blow.
Leave it AS-IS, it's good.
Since C is passing in the same name parameter to both A and B, you might be able to get what you want with virtual inheritance. V below is defined to be a common base class for A, B, and C, but with virtual inheritance, they all share the same instance.
class V {
public:
std::string GetName();
std::string GetName() const;
void SetName(std::string name);
protected:
std::string _name;
V () {}
V (std::string n) : _name(n) {}
~V () {}
};
class A : virtual public V, public O {
//...
};
class B : virtual public V {
//...
};
class C : virtual public V, public A, public B {
public:
C (/*...otherargs,*/std::string name/*,moreargs...*/)
: V(name), A(/*...*/), B(/*...*/) {
//...
}
//...
};
I think I messed up somehow in my design because I want to keep a vector of various object types. These types all share a common base class. Example:
Class Buick: AmericanCar
{
}
Class Ford: AmericanCar
{
}
then I did:
vector<AmericanCar*> cars_i_own;
Now, I have my vector of pointers but I don't have the derived class which is what I need. I thought about adding a GetType/SetType function to the base class and then use a dynamic cast. This is clunky though. Did i use the wrong design for this?
Well, what are you trying to do with it? Get the name or cost? You would have something like:
class Car
{
public:
virtual ~Car(void) {}
virtual std::string location(void) const = 0;
virtual std::string name(void) const = 0;
virtual double cost(void) const = 0;
}
class AmericanCar
{
public:
virtual ~AmericanCar(void) {}
virtual std::string location(void) const
{
return "America";
}
}
class Buick : public AmericanCar
{
public:
virtual std::string name(void) const
{
return "Buick";
}
virtual double cost(void) const
{
return /* ... */;
}
}
class Ford : public AmericanCar
{
public:
virtual std::string name(void) const
{
return "Ford";
}
virtual double cost(void) const
{
return /* ... */;
}
}
Now you can call these methods polymorphically.
This is somewhat strange, though. You don't need a different class to store names and cost like this:
class Car
{
public:
Car(const std::string& pLocation,
const std::string& pName,
double pCost) :
mLocation(pLocation),
mName(pName),
mCost(pCost)
{
}
const std::string& location(void) const
{
return mLocation;
}
void location(const std::string& pLocation)
{
mLocation = pLocation;
}
const std::string& name(void) const
{
return mName;
}
void name(const std::string& pName)
{
mName = pName;
}
const double cost(void) const
{
return mCost;
}
void cost(double pCost)
{
mCost = pCost;
}
private:
std::string mLocation;
std::string mName;
double mCost;
}
// make cars
std::vector<Car> cars;
cars.push_back(Car("America", "Buick", /* ... */));
The purpose of inheritance / polymorphism is so you don't need to care which derived type you are dealing with.
In particular I think storing data, such as make of car, country of origin etc, encoded in a class hierarchy doesn't seem to be particularly beneficial. Does an AmericanCar do something fundamentally different from, say, a Japanese car (other than consuming more fuel, which again can be better stored in a data member)?
Why do you need to know the derived class? Normally you would have virtual functions to take care of any behavior differences between the two derived classes.
The goal is that the code using the parent class shouldn't have to know the exact class it's working with.
You can use typeid to determine the derived class:
struct Base
{
virtual ~Base() {}
};
struct Derived : public Base { };
int main()
{
Base* b = new Derived();
std::cout << typeid(*b).name() << std::endl;
}
This outputs: "Derived".
But, usually with polymorphism the point is that you shouldn't be concerned with this. You simply call a base-class member function and the proper derived-class member function is called at runtime.