So I have the main parent class called item and that class has 2 child classes called book and periodical. The ideas behind what I am trying to do is have a polymorphic array or a polymorphic vector that would be able to do something like this:
Now the example is in C# (but I want to do it in C++)
item [ ] items = new items [100];
items[0] = new book();
items[1] = new periodical();
for (int i = 0; i < items.size; i++ ) {
items[i].read();
}
Like I said, the small example code is in C# but I want to do this in C++ but I am not sure how to go about going it. I wanted to use arrays but I'm my research, I haven't found a clear way of how to accomplish this. I also thought if vectors were possible to use or this but I was not sure about that either.
Here is an example (if you have questions let me know):
#include <iostream>
#include <memory>
#include <vector>
class Item
{
public:
virtual ~Item() = default; // base classes with virtual methods must have a virtual destructor
virtual void read() = 0;
};
class Book final :
public Item
{
public:
void read() override
{
std::cout << "book read\n";
}
};
class Periodical final :
public Item
{
public:
void read() override
{
std::cout << "periodical read\n";
}
};
int main()
{
std::vector<std::unique_ptr<Item>> items;
// use emplace_back for temporaries
items.emplace_back(std::make_unique<Book>());
items.emplace_back(std::make_unique<Periodical>());
// range based for loop over unique_pointers in items
// use const& so item cannot be modified and & to avoid copy of unique_ptr (unique_ptr doesn't have a copy constructor)
for (const auto& item : items)
{
item->read();
}
return 0;
}
I have a base class A and in this class, there is a vector of the derived class B, and I add class C objects to this list (C is a derived class of B).
But now I am not able to access any variable either from B or C.
My class structure goes like this:
Skill.h
class Skill
{
public:
Skill()
{
}
vector <AttackSkill*> attacks;
vector <UtilitySkill*> utilities;
vector <MoveSkill*> movement;
};
AttackSkill.h
#pragma once
#include "Skill.h"
class AttackSkill :
public Skill
{
public:
AttackSkill()
{
}
string skillName;
int dmgMod;
int baseAcc;
};
One of the skills
#pragma once
#include "AttackSkill.h"
class Axeblade :
public AttackSkill
{
public:
Axeblade()
{
skillName = "Axeblade";
dmgMod = 0;
baseAcc = 72;
}
};
This is how to add new skill
attacks.push_back(new Axeblade);
I just want to be able to access variables.
Example:
"skillPtr" is a pointer to Skill object
for (int i = 0; i < skillPtr->attacks.size(); i++) //No problem here
{
cout << "Skill " << i << ") " << skillPtr->attacks[i]->skillName << endl;
}
Error C2039 'skillName': is not a member of 'Skill'
I am doing some guesswork here since the question is not fully specific but it might help…
Your class Skill contains three vectors (aggregation) and it’s inherited by subclasses defining skill types (inheritance). You should break these two principles apart. There should be one class containing the vectors for a character, let me call it SkillSet. (By the way, you should never issue using namespace in a header file.)
class SkillSet
{
public:
std::vector <AttackSkill *> attacks;
std::vector <UtilitySkill *> utilities;
std::vector <MoveSkill *> movement;
};
Then there will be another base class for all skills which would contain the properties which all skills have:
class Skill
{
public:
std::string skillName;
};
Then you can inherit this new Skill class:
class AttackSkill :
public Skill
{
public:
int dmgMod;
int baseAcc;
};
class Axeblade :
public AttackSkill
{
public:
Axeblade()
{
skillName = "Axeblade";
dmgMod = 0;
baseAcc = 72;
}
};
After creating and filling a SkillSet object:
SkillSet hero0;
hero0.attacks.push_back(new Axeblade);
You can simply access its public members:
std::cout << hero0.attacks[0]->skillName;
See the example of my code.
A few more notes to consider:
You don’t need vectors of pointers, you can put the objects directly to the vector. A vector is not a plain array.
Instead of making the properties public, consider using setters and getters.
Your code contains empty constructors. There is no need to write a constructor that is empty.
On the other hand, if your code contains objects created using new, you should delete them, e.g. in a destructor.
I am a c++ beginner and learning about smart pointers and inheritance. I have a base class Shape(abstract) and as derived classes I have Triangle, Isosceles and Equilateral.
My idea is to print appropriate print message for each class according to the type which is pointed the base class, which I have declared in the main() as shown below.
#include <iostream>
#include <memory>
class Shape
{
public:
virtual const void triangle()const = 0;
virtual ~Shape(){ std::cout<<"Shape Deleted\n"; }
};
class Triangle: public Shape
{
public:
virtual const void triangle()const override
{ std::cout<<"I am a triangle\n"; }
virtual ~Triangle(){ std::cout<<"Triangle Deleted\n"; }
};
class Isosceles : public Triangle
{
public:
virtual const void triangle()const override
{ std::cout<<"I am an isosceles triangle\n"; }
virtual ~Isosceles(){ std::cout<<"Isosceles Deleted\n"; }
};
class Equilateral: public Isosceles
{
public:
virtual const void triangle()const override
{ std::cout<<"I am an equilateral triangle\n"; }
virtual ~Equilateral(){ std::cout<<"Equilateral Deleted\n"; }
};
When I use traditional way of creating a pointer object using new key word, the distructors of all classes works perfectly(out put is given below).
The main() was:
int main()
{
Shape *Obj[3];
Obj[0] = new Equilateral();
Obj[1] = new Isosceles();
Obj[2] = new Triangle();
for(auto it: Obj)
it->triangle();
delete Obj[0];
return 0;
}
The output is here
But when I change to std::shared_ptr things are different which I could not understand.
The main() was:
int main()
{
std::shared_ptr<Shape> obj[3];
obj[0] = std::make_shared<Equilateral>();
obj[1] = std::make_shared<Isosceles>();
obj[2] = std::make_shared<Triangle>();
for(auto it: obj)
it->triangle();
return 0;
}
The Output Now:
Can anybody help me figure it out, why this happens?
may thanks in advance.
When you use raw pointers you only destroy the first object:
delete Obj[0];
and make other 2 leak, while when you use std::shared_ptr all 3 objects cleaned properly. This is exact reason why using smart pointers is recommended practice.
Actually your second snippet is correct and the output is exactly as expected.
Your first snippet has a bug: you just delete obj[0];. What about obj[1] and obj[2]? If you delete all members of the array, you'll see that the difference between the outputs of two code samples vanish.
The good thing about smart pointers is that they are supposed to be used in a "fire-and-forget" manor.
Finally, read that book of yours with greater caution: you need to master the order of construction and destruction before starting anything about OOP.
Instead of "Car" is there a way to set the name variable of each object according to its class, for example "Turbo 01" or "Tank 02" or "Buggy 03", where id contains the amount of vehicles created.
#include <iostream>
#include <string>
#include <sstream>
static int id = 0; //Total Number of cars right now
class Car
{
private:
std::string name;
Car()
{
std::ostringstream tmp;
std::string temp;
tmp << "Car" << ++id;
temp = tmp.str();
}
Car(std::string name){this->name=name; id++;}
};
class Turbo : public Car()
{
Turbo():Car()
{
}
Turbo(std::string name):Car(name);
{
}
};
First, let's make sure that the class Car compiles by providing the two required template arguments std::array : type and size. For example: std::array<int, 10>.
The problem is that Turbo needs a valid constructor for its base type Car before it can do anythin else. There are two ways, for it to work:
Either you design Car so that there is a default consructor (i.e.without parameters)
Or you put the constructor for Car in the initialisezer list of the Turbo.
For your edited question, the problem is that the Car constructor must be visible for the derived class, so either public or protected, but not private. You can also use default parameters to get rid of redundant code.
Here a solution:
class Car
{
private:
static int id; //Total Number of cars right now SO MEK IT a static class member
std::string name;
public: // public or protected so that derived classes can access it
Car(std::string n="Car") // if a name is provided, it will be used, otherwhise it's "Car".
{
std::ostringstream tmp;
std::string temp;
tmp << n << ++id;
name = tmp.str(); // !! corrected
}
};
int Car::id = 0; // initialisation of static class member
class Turbo : public Car
{
public: // !! corrected
Turbo(std::string n="Turbo") :Car(n) // !!
{ }
};
Lets say I have a base class with 100 children:
class Base {
virtual void feed();
...
};
class Child1 : public Base {
void feed(); //specific procedure for feeding Child1
...
};
...
class Child100 : public Base {
void feed(); //specific procedure for feeding Child100
...
};
At runtime I want to read a file that contains which children to create and feed. Lets say I've read the file and the vector of strings "names" contains the names of the child classes (ie. Child1, Child4, Child99). Now I'm going to iterate through these strings, create an instance of the specific child, and feed it with its specific feeding procedure:
vector<Base *> children;
for (vector<string>::iterator it = names.begin(); it != names.end(); ++it) {
Base * child = convert_string_to_instance(*it)
child->feed()
children.push_back(child);
}
How would I create the function convert_string_to_instance() such that if it takes in the string "Child1" it returns a "new Child1", if the string argument is "Child4" it returns a "new Child4", etc
<class C *> convert_string_to_instance(string inName) {
// magic happens
return new C; // C = inName
// <brute force?>
// if (inName == "Child1")
// return new Child1;
// if (inName == "Child2")
// return new Child2;
// if (inName == "Child3")
// return new Child3;
// </brute force>
}
C++ does not provide a method for dynamic construction of class instances like this. However, you may be able to use code generation to generate the "brute force" code (like you showed above) from a list of classes. Then, #include the generated code in your convert_string_to_instance method.
You can also set up your project build system to rebuild the generated code anytime the list of classes changes.
I asked a question entitled automatic registration of object creator function with a macro that has the following example program that runs:
#include <map>
#include <string>
#include <iostream>
struct Object{ virtual ~Object() {} }; // base type for all objects
struct ObjectFactory {
static Object* create(const std::string& id) { // creates an object from a string
const Creators_t::const_iterator iter = static_creators().find(id);
return iter == static_creators().end() ? 0 : (*iter->second)(); // if found, execute the creator function pointer
}
private:
typedef Object* Creator_t(); // function pointer to create Object
typedef std::map<std::string, Creator_t*> Creators_t; // map from id to creator
static Creators_t& static_creators() { static Creators_t s_creators; return s_creators; } // static instance of map
template<class T = int> struct Register {
static Object* create() { return new T(); };
static Creator_t* init_creator(const std::string& id) { return static_creators()[id] = create; }
static Creator_t* creator;
};
};
#define REGISTER_TYPE(T, STR) template<> ObjectFactory::Creator_t* ObjectFactory::Register<T>::creator = ObjectFactory::Register<T>::init_creator(STR)
namespace A { struct DerivedA : public Object { DerivedA() { std::cout << "A::DerivedA constructor\n"; } }; }
REGISTER_TYPE(A::DerivedA, "A");
namespace B { struct DerivedB : public Object { DerivedB() { std::cout << "B::DerivedB constructor\n"; } }; }
REGISTER_TYPE(B::DerivedB, "Bee");
namespace C { struct DerivedC : public Object { DerivedC() { std::cout << "C::DerivedC constructor\n"; } }; }
REGISTER_TYPE(C::DerivedC, "sea");
namespace D { struct DerivedD : public Object { DerivedD() { std::cout << "D::DerivedD constructor\n"; } }; }
REGISTER_TYPE(D::DerivedD, "DEE");
int main(void)
{
delete ObjectFactory::create("A");
delete ObjectFactory::create("Bee");
delete ObjectFactory::create("sea");
delete ObjectFactory::create("DEE");
return 0;
}
compile and run output is:
> g++ example2.cpp && ./a.out
A::DerivedA constructor
B::DerivedB constructor
C::DerivedC constructor
D::DerivedD constructor
If you have a lot of classes, you'd usually choose a less brute force approach. A trie or hash_map between class names and factory functions is a good approach.
You can use a codegen approach as suggested by Greg to build this factory table, for example doxygen can parse your source code and output a list of all classes in xml format along with inheritance relationships, so you could easily find all classes deriving from a common "interface" base class.
It sounds like you might be using subclasses for things that should be encoded as fields.
Instead of coding the different behaviour in 100 classes, consider building a look-up table with rules/constants/function-pointers that allow you to implement the proper behaviour from one class.
For example, instead of:
class SmallRedSquare : public Shape {...};
class SmallBlueSquare : public Shape {...};
class SmallBlueCircle : public Shape {...};
class SmallRedCircle : public Shape {...};
class BigRedSquare : public Shape {...};
class BigBlueSquare : public Shape {...};
class BigBlueCircle : public Shape {...};
class BigRedCircle : public Shape {...};
try:
struct ShapeInfo
{
std::string type;
Size size;
Color color;
Form form;
};
class Shape
{
public:
Shape(std::string type) : info_(lookupInfoTable(type)) {}
void draw()
{
// Use info_ to draw shape properly.
}
private:
ShapeInfo* lookupInfoTable(std::string type) {info_ = ...;}
ShapeInfo* info_;
static ShapeInfo infoTable_[];
};
const ShapeInfo Shape::infoTable_[] =
{
{"SmallRedSquare", small, red, &drawSquare},
{"SmallBlueSquare", small, blue, &drawSquare},
{"SmallRedCircle", small, red, &drawCircle},
{"SmallBlueCircle", small, blue, &drawCircle},
{"BigRedSquare", big, red, &drawSquare},
{"BigBlueSquare", big, blue, &drawSquare},
{"BigBlueCircle", big, red, &drawCircle},
{"BigRedCircle", big, blue, &drawCircle}
}
int main()
{
Shape s1("SmallRedCircle");
Shape s2("BigBlueSquare");
s1.draw();
s2.draw();
}
This idea might not be applicable to your problem, but I figure it couldn't hurt to present it anyway. :-)
My idea is like the Replace Subclass with Fields refactoring, but I go a bit further.
You can abuse the preprocessor and set up some static class members that register your classes with a factory via a hash_map like Ben describes. If you have visual studio, look at how DECLARE_DYNCREATE is implemented in MFC. I've done something similar to implement a class factory. Non-standard for sure but since C++ does not offer any kind of support for this type of mechanism any solution is probably going be non-standard.
Edit
I said in a comment earlier I was working on documenting a scaled down version of something I had done. The scaled down version is still rather large so I posted it here. If there is enough interest I can copy/paste it on this site. Let me know.
This is the skeleton of a horrible, horrible way to do it:
class Factory {
public:
virtual Base * make() = 0;
};
template<typename T> class TemplateFactory : public Factory {
public:
virtual Base * make() {
return dynamic_cast<Base *>(new T());
}
};
map<string, Factory *> factories;
#define REGISTER(classname) factories[ #classname ] = new TemplateFactory<classname>()
Then call REGISTER(classname); for every relevant derived class of Base, and use factories["classname"]->make() to get a new object of type classname. Obvious flaws with the above code as written include massive potential for memory leaks, and the general awfulness of combining macros and templates.
Behold the mighty Boost.
The one thing you have to do in order to use my solution is to add a new member to all your classes, and that is a static const string that contains the name of the class. There are probably other ways to do it too, but that's what I have right now.
#include <iostream>
#include <vector>
#include <string>
#include <boost/fusion/container/list/cons.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/view/iterator_range.hpp>
using namespace std;
using boost::fusion::cons;
class Base { virtual void feed(){ } };
class Child1 : public Base{
void feed(){ }
public:
static const string name_;
};
const string Child1::name_ = "Child1";
class Child3 : public Base{
void feed(){ }
public:
static const string name_;
};
const string Child3::name_ = "Child3";
//...
class Child100 : public Base{
void feed(){ }
public:
static const string name_;
};
const string Child100::name_ = "Child100";
// This is probably the ugliest part, but I think it's worth it.
typedef cons<Child1, cons<Child3, cons<Child100> > > MyChildClasses;
typedef vector<Base*> Children;
typedef vector<string> Names;
struct CreateObjects{ // a.k.a convert_string_to_instance() in your example.
CreateObjects(Children& children, string name) : children_(&children), name_(name){ }
template <class T>
void operator()(T& cs) const{
if( name_ == cs.name_ ){
cout << "Created " << name_ << " object." << endl;
(*children_).push_back(new T);
}else{
cout << name_ << " does NOT match " << cs.name_ << endl;
}
}
Children* children_;
string name_;
};
int main(int argc, char* argv[]){
MyChildClasses myClasses;
Children children;
Names names;
names.push_back("Child1");
names.push_back("Child100");
names.push_back("Child1");
names.push_back("Child100");
// Extra test.
// string input;
// cout << "Enter a name of a child class" << endl;
// cin >> input;
// names.push_back(input);
using namespace boost::fusion;
using boost::fusion::begin;
using boost::fusion::for_each;
for(Names::iterator namesIt = names.begin(); namesIt != names.end(); ++namesIt){
// You have to know how many types there are in the cons at compile time.
// In this case I have 3; Child1, Child3, and Child100
boost::fusion::iterator_range<
result_of::advance_c<result_of::begin<MyChildClasses>::type, 0>::type,
result_of::advance_c<result_of::begin<MyChildClasses>::type, 3>::type
> it(advance_c<0 >(begin(myClasses)),
advance_c<3>(begin(myClasses)));
for_each(it, CreateObjects(children, *namesIt));
}
cout << children.size() << " objects created." << endl;
return 0;
}