C++ a way to get all inherited classes info - c++

So i have this part of code
class Robot
{
public: string Name;
public: explicit Robot(const string& Name) { this->Name = Name; }
public: Robot() { Name = "Robotic"; }
public: virtual ~Robot() = default;
public: virtual vector<string> GetCapabilities() = 0;
public: friend ostream& operator << (ostream&, const Robot&);
};
class TalkingRobot : virtual public Robot
{
public: explicit TalkingRobot(const string& Name) { this->Name = Name; }
public: virtual ~TalkingRobot() = default;
public: vector<string> GetCapabilities() { return { "Talking" }; }
};
class WalkingRobot : virtual public Robot
{
public: explicit WalkingRobot(const string& Name) { this->Name = Name; }
public: virtual ~WalkingRobot() = default;
public: vector<string> GetCapabilities() { return { "Walking" }; }
};
class VaxBot : public TalkingRobot, public WalkingRobot
{
public: explicit VaxBot(const string& Name):TalkingRobot(Name), WalkingRobot(Name) { this->Name = Name; }
public: virtual ~VaxBot() = default;
public: vector<string> GetCapabilities() { return { "Talking","Walking" }; }
};
They have a virtual function GetCapabilites().
Is there a way to rewrite GetCapabilites() in my VaxBot class to return all the inherited classes return values so that i dont have to explicitly write them like i did in here?

There isn't a simple one-line way in standard C++ to implement this sort of thing. For example, there is no way for a derived class to iterate over all its base classes, and call some member function in every base to collect the results, without explicitly naming all the bases/members separately.
It is possible to call the inherited functions, and collect their results into a single vector. For example;
std::vector<std::string> VaxBot::GetCapabilities()
{
std::vector<std::string> values(TalkingRobot::GetCapabilities());
std::vector<std::string> more_values(WalkingRobot::GetCapabilities());
values.insert(values.end(), more_values.begin(), more_values.end());
return values;
}
The above can be extended if you have more than two such bases. That means explicitly replicating code but, as I said in my opening paragraph, there is no way to implement this sort of machinery implicitly.
There are other problems with your code, but you haven't asked about those, so I won't address them. And, for readability, don't use the text public: on every line. Posting code that is unnecessarily unreadable is an effective way to reduce your chances of getting useful help, since it sets other people's teeth on edge.

class Robot
{
public: string Name;
public: vector<string> Capabilities;
public: explicit Robot(const string& Name) { this->Name = Name; }
public: Robot() { Name = "Robotic"; }
public: virtual ~Robot() = default;
public: vector<string> GetCapabilities() { return this->Capabilities; }
public: friend ostream& operator << (ostream&, const Robot&);
};
class TalkingRobot : virtual public Robot
{
public: explicit TalkingRobot(const string& Name) {
this->Name = Name;
this->Capabilities.push_back("Talking");
}
public: virtual ~TalkingRobot() = default;
};
class WalkingRobot : virtual public Robot
{
public: explicit WalkingRobot(const string& Name) {
this->Name = Name;
this->Capabilities.push_back("Walking");
}
public: virtual ~WalkingRobot() = default;
};
class VaxBot : public TalkingRobot, public WalkingRobot
{
public: explicit VaxBot(const string& Name):TalkingRobot(Name), WalkingRobot(Name) { this->Name = Name; }
public: virtual ~VaxBot() = default;
};
You could utilize multiple inheritance constructors to store Capabilities.

Related

return single object from unique_ptr vector in c++

I'm making a command applaction I have base class that other commands class inherate.
struct BaseCommand {
public:
virtual ~BaseCommand() {}
int id = 0;
std::string name = "Base Command";
std::string description = "Base Command";
BaseCommand();
virtual std::string getName();
virtual int getId();
virtual std::string getDescription();
private:
virtual void init();
virtual void run();
};
class HelpCommand: public BaseCommand {
public:
HelpCommand();
std::string name = "help";
std::string description = "output help";
int id = 1;
virtual std::string getName();
int getId() {return this->id;};
virtual std::string getDescription();
private:
virtual void init();
virtual void run();
};
class ProductCommand: public BaseCommand {
public:
ProductCommand();
std::string name = "prod";
std::string description = "product";
int id = 2;
virtual std::string getName();
int getId() {return this->id;};
virtual std::string getDescription();
private:
virtual void init();
virtual void run();
};
and in my main, I push my subclass to a vector. my goal is to get the command by its name how do I do that and get the only command and assign it to a variable
std::vector<std::unique_ptr<BaseCommand>> commands;
// lett's push our commands...
commands.emplace_back(new HelpCommand);
commands.emplace_back(new ProductCommand);
std::string command = 'prod';
// what's the type should be for selectedCommand?
?? selectedCommand;
for (int i = 0; i < commands.size(); ++i) {
if (commands[i]->getName() == command) {
selectedCommand = commands[i];
}
}
I can't seem to determine which type should the selectedCommand be. please what I'm missing here?
I can't seem to determine which type should the selectedCommand be. please what I'm missing here?
You can't "override" member variables.
Your derived classes have two of each member variable with the same name; one in the base class and one in the derived class.
When you access the objects through a pointer to BaseCommand, you get the members from BaseCommand and not those from the dervied class.
Redesign so these are only members of the base, and make the accessors non-virtual:
struct BaseCommand {
public:
virtual ~BaseCommand() {}
const std::string& getName() const { return name; }
int getId() const { return id; }
const std::string& getDescription() const { return description; }
protected:
// Let only derived classes create base instances.
BaseCommand(int id,
const std::string& name,
const std::string& description)
: id(id), name(name), description(description)
{}
private:
int id = 0;
std::string name = "Base Command";
std::string description = "Base Command";
virtual void init();
virtual void run();
};
class HelpCommand: public BaseCommand {
public:
HelpCommand() : BaseCommand(1, "help", "output help") {}
private:
virtual void init();
virtual void run();
};
class ProductCommand: public BaseCommand {
public:
ProductCommand() : BaseCommand(2, "prod", "product") {}
private:
virtual void init();
virtual void run();
};

How should i store some different class objects in a template class?

So, I have to create a template class that will store objects of another class, like in a vector or a list. I decided to write a simple example, like an atlas for some animals.
Until now I got this, but I can not instantiate my vector with animals objects. I get this error:
main.cpp|60|error: could not convert <'brace-enclosed initializer list >()' from 'brace-enclosed initializer list>' to 'Animal'
The animal class is just a base class for the other classes like "bird".
#include <iostream>
#include <assert.h>
#include <list>
using namespace std;
class Animal {
protected:
std::string m_name;
Animal (std::string name): m_name {name} {}
public:
virtual std::string regn() const { return "???"; }
virtual ~Animal(){
cout << "Destructor animal"<<'\n';}
};
class Nevertebrate : public Animal{
public:
virtual std::string regn() const { return "nevertebrate";}
virtual ~Nevertebrate();
};
class Vertebrate: public Animal {
protected:
/* std::string m_name;
Vertebrate (std::string name)
:m_name {name} {} */
Vertebrate (std::string name)
: Animal {name} {}
public:
virtual std::string regn() const { return "vertebrate";}
virtual ~Vertebrate(){
cout<<"Destructor vertebrate"<<'\n';};
};
class bird: public Vertebrate {
public:
bird(std::string name)
: Vertebrate{ name }{}
void set_name (std::string nume){
m_name = nume;}
std::string get_name(){
return m_name;}
virtual std::string regn() const {return "pasare";}
virtual ~bird (){
cout << "destructor bird"<<'\n';}
};
template <class T>
class Atlas
{
private:
int m_length{};
T* m_data{};
public:
Atlas(int length)
{
assert(length > 0);
m_data = new T[length]{};
m_length = length;
}
Atlas(const Atlas&) = delete;
Atlas& operator=(const Atlas&) = delete;
~Atlas()
{
delete[] m_data;
}
void erase()
{
delete[] m_data;
m_data = nullptr;
m_length = 0;
}
T& operator[](int index)
{
assert(index >= 0 && index < m_length);
return m_data[index];
}
int getLength() const;
};
template <class T>
int Atlas<T>::getLength() const // note class name is Array<T>, not Array
{
return m_length;
}
int main()
{
Atlas<Animal> AtlasAnimal(10);
return 0;
}

Method of Abstract Class used by derived Class

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

New derived class from abstract classes

I have encountered a problem with creating new class objects.
The abstract class is called SimpleList, currently doesn't do anything on its own.
template<class T>
class SimpleList {
public:
string ListName;
SimpleList(){
};
string getName(){
return ListName;
};
};
template<class T>
class Queue : public SimpleList<T> {
public:
string ListName;
Queue(string& name){
ListName = name;
}
string getName(){
return ListName;
}
};
And here is where I am attempting to assign 'pQLi' to a new Queue, where Queue is a derived class.
SimpleList<int> *pQLi;
if (indicator == 'i' ){
pQLi = new Queue<int>(name1);
}
But whatever I do to print out the name of pQLi (or access any data from it, but in the simplest case ) outside of the Queue, only ' ' is coming out. For example, if I do this
cout <<(*pQLi).getName() <<"\n";
Instead of printing out the ListName, a blank character comes out
its as simple as it is. Make your base class getName() virtual as follows. Since you are care of the content of pointer, you need a late binding of the object.
template<class T>
class SimpleList
{
public:
string ListName;
SimpleList() = default;
virtual string getName(){
return ListName;
};
};
However, I do not understand, why you need a template class for this. You have not used the type(T) anywhere.
And try to use initializer_list whenever possible and smart pointers are good to use in following cases. I have made a small correction as follows. Hope this has answered your question.
#include <iostream>
template<class T>
class SimpleList
{
private:
std::string ListName;
public:
SimpleList() = default;
virtual ~SimpleList(){}
virtual const std::string& getName()const
{ return ListName; };
};
template<class T>
class Queue : public SimpleList<T>
{
private:
std::string ListName;
public:
Queue(const std::string& name)
:ListName(name) {}
const std::string& getName()const
{ return ListName; }
};
int main()
{
SimpleList<int> *pQLi;
char indicator = 'i';
std::string name1 = "nothing";
if (indicator == 'i' ){
pQLi = new Queue<int>(name1);}
std::cout <<(*pQLi).getName() <<"\n";
delete pQLi;
pQLi = nullptr;
return 0;
}

C++ storing base and derived class objects together

I Have two classes:
First:
class Thing {
public:
int code;
string name;
string description;
int location;
bool canCarry;
Thing(int _code, string _name, string _desc, int _loc, bool _canCarry) {
code = _code;
name = _name;
description = _desc;
location = _loc;
canCarry = _canCarry;
}
};
Second:
class Door: public Thing {
private:
bool open;
public:
int targetLocation;
Door(int _code, string _name, string _desc, int _loc, int _targetLoc) :
Thing(_code, _name, _desc, _loc, false) {
open = false;
targetLocation = _targetLoc;
}
void Use() {
open = true;
}
void Close() {
open = false;
}
bool isOpen() {
return open;
}
};
Forget private/public atributes...
I need to store some objects of base class and some objects of derived class,
something like this:
vector < Thing*> allThings;
things.push_back(new Thing(THING1, "THING1", "some thing", LOC1, true));
things.push_back(new Door(DOOR1, "DOOR1", "some door", LOC1, LOC2));
But in this case, functions Use(), Open(), and isOpen() will not be reachable because of slicing..
Do you have some suggestions, how to store these objects together without creating new structure of vector<Thing*> and vector<Door*>??
Thanks
A good solution to a problem when you need a container of objects with polymorphic behavior is a vector of unique pointers:
std::vector<std::unique_ptr<Thing>>
There would be no slicing in this situation, but you would have to figure out when it's OK to call Use(), Open(), and isOpen().
If you can move the methods from the derived class into the base, go for it; if you cannot do that because it makes no sense for a Thing to have isOpen(), consider using a more advanced solution, such as the Visitor Pattern:
class Thing;
class Door;
struct Visitor {
virtual void visitThing(Thing &t) = 0;
virtual void visitDoor(Door &d) = 0;
};
class Thing {
...
virtual void accept(Visitor &v) {
v.visitThing(*this);
}
};
class Door : public Thing {
...
virtual void accept(Visitor &v) {
v.visitDoor(*this);
}
}
Store pointers instead of instances, and declare public and protected methods as virtual in the base class(es).