Member values not accessed in vector of instances of different subclasses - c++

Jumping off of the above question Making a vector of instances of different subclasses : when implementing a vector of (pointers to) different subclasses (initialized as vector<Base*> objects), I expect to be able to access the correct member variables based on the subclass called.
Below is sample code:
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Entity {
public:
int index;
Entity() {};
virtual ~Entity() {};
virtual void hit() = 0;
};
class Mesh : public Entity {
public:
int index;
Mesh(int x) {this->index=x;};
virtual void hit() {}
};
int main() {
vector<unique_ptr<Entity>> objects;
objects.push_back(unique_ptr<Entity>(new Mesh(35)));
objects.push_back(unique_ptr<Entity>(new Mesh(10)));
for ( int i = 0 ; i < objects.size() ; i++ )
cout << objects[i]->index << endl;
return 0;
}
Where I expect
35
10
to be printed, meanwhile I get instead.
0
0
How can I access the correct member variable values in this scenario?

The problem is due to a misunderstanding on inheritance. If you redefine your Mesh as follows, it would work as expected:
class Mesh : public Entity {
public:
//int index; // No don't redefine: here you'd have two different indexes
Mesh(int x) {this->index=x;};
void hit() override {} // extraa safety: use override instead of virtual to be sure to override
};
Online demo
Not related to the problem, but some more thoughts:
You can of course only use the interface of the base class (here Entity).
It is not very prudent to expose the index member publicly. A safer option would be to have it private, and access it via a public getter. If the index should be set only at construction, the Entity constructor should take care of it, otherwise you could consider a public setter.

Related

C++ polymorphism: how to create derived class objects

I have an abstract base class called BaseStrategy. It contains one pure virtual function calculateEfficiency(). There are two classes ConvolutionStrategy and MaxPoolStrategy which derive from this base class and implement their own specific version of calculateEfficiency().
Here is some code:
class BaseStrategy {
public:
explicit BaseStrategy();
virtual ~BaseStrategy() = default;
private:
virtual double calculateEfficiency(mlir::Operation* op) = 0;
};
class ConvolutionStrategy : public BaseStrategy {
private:
double calculateEfficiency(mlir::Operation* op)
{
//some formula for convolution
return 1;
}
};
class MaxPoolStrategy : public BaseStrategy {
private:
double calculateEfficiency(mlir::Operation* op)
{
//some formula for MaxPool
return 1;
}
};
Now I have another class called StrategyAssigner. It has method calculateAllLayerEfficiencies() whose purpose is to iterate over all layers in a network. Depending on the type of layer there is a switch statement and should call the correct calculateEfficiency() depending on the layer type.
class StrategyAssigner final {
public:
explicit StrategyAssigner(){};
public:
void calculateAllLayerEfficiencies() {
// Logic to iterate over all layers in
// a network
switch (layerType) {
case Convolution:
// Call calculateEfficiency() for Convolution
break;
case MaxPool:
// Call calculateEfficiency() for MaxPool
break;
}
};
}
int main ()
{
StrategyAssigner assigner;
assigner.calculateAllLayerEfficiencies();
}
My question is, should I store references of objects Convolution and MaxPool in the class StrategyAssigner so that I can call the respective calculateEfficiency().
Or could you suggest a better way to call calculateEfficiency(). I don't really know how to create the objects (stupid as that sounds).
I can't make calculateEfficiency() static as I need them to be virtual so that each derived class can implemented its own formula.
If you included complete code I could give a more detailed answer, but you need to store BaseStrategy pointers that are initialized with derived class instances. Here's an example made from some of your code:
std::vector<std::unique_ptr<BaseStrategy>> strategies;
strategies.emplace_back(new ConvolutionStrategy);
strategies.emplace_back(new MaxPoolStrategy);
for (int i = 0; i < strategies.size(); ++i) {
std::unique_ptr<BaseStrategy>& pStrat = strategies[i];
pStrat->calculateEfficiency(...);
}
Note that this won't compile because I don't have enough details from the code you posted to make it so, but this shows how to exploit polymorphism in the way that you need.
Also, I used smart pointers for memory management; use these at your discretion.
You can indeed use runtime polymorphism here:
Declare ~BaseStrategy virtual (you are already doing it ;-)
If you are never going to instantiate a BaseStrategy, declare one of its methods as virtual pure, e.g. calculateEfficiency (you are already doing it as well!). I would make that method const, since it doesn't look it's going to modify the instance. And it will need to be public, because it will need to be accessed from StrategyAnalyser.
Declare calculateEfficiency as virtual and override in each of the subclasses. It could also be final if you don't want subclasses to override it.
I'd keep a std::vector of smart pointers to BaseStrategy at StrategyAssigner. You can use unique_ptrs if you think this class is not going to be sharing those pointers.
The key point now is that you create heap instances of the subclasses and assign them to a pointer of the base class.
class StrategyAssigner final {
public:
void addStrategy(std::unique_ptr<BaseStrategy> s) {
strategies_.push_back(std::move(s));
}
private:
std::vector<std::unique_ptr<BaseStrategy>> strategies_{};
};
int main()
{
StrategyAssigner assigner;
assigner.addStrategy(std::make_unique<ConvolutionStrategy>());
}
Then, when you call calculateEfficiency using any of those pointers to BaseStrategy, the runtime polymorphism will kick in and it will be the method for the subclass the one that will be actually called.
class ConvolutionStrategy : public BaseStrategy {
private:
virtual double calculateEfficiency() const override {
std::cout << "ConvolutionStrategy::calculateEfficiency()\n";
return 10;
}
};
class MaxPoolStrategy : public BaseStrategy {
private:
virtual double calculateEfficiency() const override {
std::cout << "MaxPoolStrategy::calculateEfficiency()\n";
return 20;
}
};
class StrategyAssigner final {
public:
void calculateAllLayerEfficiencies() {
auto sum = std::accumulate(std::cbegin(strategies_), std::cend(strategies_), 0,
[](auto total, const auto& strategy_up) {
return total + strategy_up->calculateEfficiency(); });
std::cout << "Sum of all efficiencies: " << sum << "\n";
};
};
int main()
{
StrategyAssigner assigner;
assigner.addStrategy(std::make_unique<ConvolutionStrategy>());
assigner.addStrategy(std::make_unique<MaxPoolStrategy>());
assigner.calculateAllLayerEfficiencies();
}
// Outputs:
//
// ConvolutionStrategy::calculateEfficiency()
// MaxPoolStrategy::calculateEfficiency()
// Sum of all efficiencies: 30
[Demo]

C++ virtual inheritance and access to a public virtual method whose implementation is in a class whose inheritance is protected

I am using a virtual inheritance to create a class EditablePrimeNumberSet (a set of prime numbers) that inherits the class EditableNumberSet (a set of integers that can be incremented) while only exposing the base class NumberSet (a set of number).
(I don't want my class to expose the method add that will lead to a set that do not contain only prime numbers)
remark : it is just a simple example. I actually do not work on prime numbers. This example was just devised to illustrate the problem I am facing.
My problem is that, when I want to call the virtual method contains44 on a EditableNumberSet variable, I need to static_cast it to avoid a compilation error. It looks like the compiler finds that the direct implementation is tractable because it knows the actual type of my object but then discovers that this method is not accessible. So, actually, I am not stuck but find it curious and not elegant to do such static_cast. Are there some tips to improve my code ?
using namespace std;
class NumberSet {
public :
int size() {return myList.size();}
virtual bool contains44()
{
cout << "in base method\n";
return myList.count(44)>0;
};
protected :
set<int> myList;
};
class EditableNumberSet : public virtual NumberSet {
public :
void add(int i) {myList.insert(i);}
bool contains44() override
{
cout << "in inherited method\n";
return false;
} // 44 is not a prime number
};
class EditablePrimeNumberSet: public virtual NumberSet, protected EditableNumberSet {
public :
void addNearestPrimeNumber(int i)
{
int j=0;
//code that set j to the nearest prime number next to i...
add(j);
}
};
int main()
{
EditablePrimeNumberSet listPN;
listPN.addNearestPrimeNumber(45);
listPN.NumberSet::contains44(); // use base class method implementation
static_cast<NumberSet &>(listPN).contains44(); // use derived class method implementation
listPN.contains44(); // error: ‘virtual bool EditableNumberSet::contains44()’ is inaccessible within this context
}
If you want to expose a single name from the protected class, you can use a using declaration:
class EditablePrimeNumberSet : public virtual NumberSet, protected EditableNumberSet {
public:
using EditableNumberSet::contains44; // Expose EditableNumberSet::contains44 as
// part of EditablePrimeNumberSet's public interface
void addNearestPrimeNumber(int i)
{
int j = 0;
//code that set j to the nearest prime number next to i...
add(j);
}
};
Then when you call listPN.contains44() you invoke the inherited method.

How should I store templated functions in any container?

I have a templated Prob class that acts as a way to organize various programming problems from different problem sets. The template is the problem number. How would I go about storing different Prob objects in a vector or map?
Here is the class declaration:
template<int ProbNum>
class Prob
{
std::string
text(std::ostream& out)
{
out << "Prob" << ((ProbNum < 10) ? "0" : "") << ProbNum << ": ";
}
void solve(std::ostream& out);
};
So in other words if I want to declare an object for problem 1 of some problem set I would do
Prob<1> p1;
and then store that in a map or vector for later use so the user can call on it during runtime (since you cannot pass a runtime argument into a template).
Edit: I want to use this class as an abstract class for other Prob classes.
Edit2: Added more code for clarification.
Edit3:
Top half is Prob1.hpp
Bottom half is a driver file on how I want to use it.
#include <iostream>
#include "Prob.hpp"
template<>
void
Prob<1>::solve(std::ostream& out)
{
out << "solution to prob1";
}
/***************************************************/
#include <iostream>
#include <cstdlib>
#include "Prob.hpp"
// Finished Problems
#include "Prob1.hpp"
int
main(int argc, char* argv[])
{
Prob<1> p;
p.solve(std::cout);
}
Each instance of a template class constitutes a different type. Hence, containers like std::vector cannot hold Prob<ProbNum> for different values of ProbNum.
If you know at compile time the number of Prob<ProbNum> instances you want, and the corresponding values of the template parameter int ProbNum you could store everything into a tuple. For example:
auto mycollection = std::make_tuple(Prob<1>(), Prob<2>());
A more general solution could be to define an abstract base class for Prob. Then you can manage to store a vector of Prob<ProbNum> objects, with inhomogeneous values of int ProbNum, if you define a vector of pointers to the base class. For this to work you must provide the interface in the base class, i.e., every member of Prob<ProbNum> that you want to access through the vector of the base class, must be virtual and already declared in the base class.
Consider the following example:
#include <iostream>
#include <memory>
#include <vector>
struct base {
virtual void print() const = 0;
virtual ~base() = default;
};
template <int i>
struct derived : public base
{
virtual void print() const { std::cout << i << std::endl; }
};
int main()
{
std::vector<std::unique_ptr<base>> vec;
vec.emplace_back(new derived<1>());
vec.emplace_back(new derived<3>());
vec.emplace_back(new derived<5>());
for (auto& el : vec)
el->print();
return 0;
}
The variable vec is essentially a vector of pointers to objects of type derived<i>, with inhomogeneous values of i. Because base::print() is virtual, it correctly resolves to the corresponding method of the derived<i> class.
Notice that I used a smart pointer to avoid memory leaking.
Also, it is important to declare virtual the destructor of base, see the discussion Why should I declare a virtual destructor for an abstract class in C++?.

Vector of an abstract class that access the derived classes of the abstract one ! How?

ACTUAL PROBLEM:
have an Abstract Class operations that inherits from VAR Class , which then all the operations derived class(out,sleep,Add) inherit from the operations class. FSM Class inherits from Var also, so That I want one instance of VAR class inside my program.
I am trying to make vector < pair< string, int>> var as a shared data between the FSM class and the Operations class and its deviates . I initialized the var in the main through the FSM class .
Each time we call the exist function in VAR through Class operation , it returns it doesn't exits cause it is empty ! How can I overcome this?
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
using namespace std;
class VAR
{
public:vector<pair<string, int>> var;
VAR()
{}
~VAR(){}
void createVar(string x,int y)
{}
void setVarValue(string& x, int y)
{}
int getVarValue(string x){}
bool exits(string& name)
{}
class operations : virtual public VAR
{
public:
operations()
{}
void virtual excute() = 0;
};
class Out :public virtual operations
{
};
class Add :public virtual operations
{
};
class FSM :public virtual VAR, public virtual transition
{
void intialize()
{
createVar("X", 1);
createVar("Y", 5);
}
};
void main()
{
FSM x;
pair<state, vector<pair<state, int>>> p1;
pair<state, int>p2;
x.intialize();
p2.first.name = "b";
p2.second = 3;
p1.first.name = "a";
p1.second.push_back(p2);
x.trans.push_back(p1);
x.trans[0].first.instructionList.push_back(new Add("X=X+Y"));
x.trans[0].first.instructionList.push_back(new Out("X"));
x.trans[0].first.exec_all();//wrong output cause exist() returns false
}
Not all shapes are usefully characterised by a length, so it doesn't make sense to want to get the length of all shapes. For example, a circle might have a radius or a diameter, but talking about the length of a circle would get blank looks from most people.
The usual point of a base class is that it provides functionality that are relevant to all shapes. So a member function like draw() may be relevant to all shapes (albeit, as a virtual function, each derived class can implement specifics of how it is drawn) but functions like setLength() and getLength() may not be.
Generally speaking, when starting from a pointer to base, if you need to convert it to a derived type, that is usually considered a sign of a broken design (and not just by C++ practitioners). What you really need to do is work out the set of capabilities the shape class really needs to provide, and make them general enough so it can handle the need for some specialised shapes to have a length, and a need for some other specialised shapes not to have a length.
It's hard to give a more specific answer than that as your needs (and therefore the set of capabilities your shape class needs to provide) will be specific to your application.
Oh: main() returns int, not void in standard C++. Your compiler may support void main(), but not all do, so it is usually considered a bad idea to use it.

How can I have several inherited classes together in the same array?

I have a few classes, ObjDef, PeopDef, NpcDef, and PlyDef, such that PlyDef and NpcDef each seperately inherit PeopDef, and PeopDef inherits ObjDef. Each class has functionality that builds on the class before it, so it's important that PeopDef::Tick is called before ObjDef::Tick. I have every object stored in a vector<ObjDef> object, but when the main tick loop goes through them, I want them to call the original classes' Tick, rather than ObjDef::Tick, which is what the vector<ObjDef> currently makes it do. Is there any way to do this, or do I have to have a separate vector for each class?
You can store an ObjDef pointer (ObjDef* or a smart pointer) in the vector and make the Tick method virtual.
Here's an example:
#include <iostream>
#include <vector>
#include <memory>
class ObjDef
{
public:
virtual void Tick()
{
std::cout << "ObjDef::Tick\n";
}
};
class PeopDef : public ObjDef
{
public:
virtual void Tick()
{
std::cout << "PeopDef::Tick\n";
}
};
int main()
{
std::vector<std::shared_ptr<ObjDef>> objects;
std::shared_ptr<ObjDef> obj(new ObjDef());
std::shared_ptr<ObjDef> peop(new PeopDef());
objects.push_back(obj);
objects.push_back(peop);
for (auto object : objects)
{
object->Tick();
}
return 0;
}