I get an error when I try to cast base class to derived class.
I want to access the derived classes that I have put in my components vector.
//Base and Derived
class Component
{
public:
Component();
virtual ~Component();
private:
};
class Material:public Component{...};
//in main
int textureID = gameScene.gameObjects[0].getComponent<Material>()->texture;
//game object
#pragma once
#include <vector>
#include "Component.h"
class GameObject:public Component
{
public:
GameObject();
GameObject(int otherAssetID);
~GameObject();
int assetID;
std::vector<Component> components;
void addComponent(Component otherComponent);
void deleteComponent(Component otherComponent);
template <class T>
T* getComponent() {
for (int i = 0; i < components.size(); i++)
{
if (dynamic_cast<T*>(components[i]) != nullptr)
{
T *test = dynamic_cast<T*>(components[i]);
return test;
}
}
return nullptr;
}
private:
};
std::vector<Component> can not contain objects of class other than Component itself. If you add a Material object to the vector, the Component part of the Material will be stored. That problem is known as the object slicing problem.
You probably want to make a vector holding pointers to the base polymorphic class.
::std::vector<::std::unique_ptr<Componenet>> components;
also dynamic_cast is expensive so you may want to call it only once storing returned value:
T * const test = dynamic_cast<T*>(components[i].get());
if(test)
{
return test;
}
Related
TL;DR
I am trying to pass a subclass into a function that expects the subclass's base class and then store a unique pointer of that base class in a vector in a third, completely separate class.
(C++ 11 and higher)
End TL;DR
I have 3 classes total and then my int main().
The base (abstract) class has a constructor and a virtual function.
The base class constructor is implemented, the virtual function is not.
The second class is the subclass to the base class.
It implements its own constructor and calls the base constructor.
The second part of the sub class is the concrete implementation of the virtual base class function.
I then have a third class that has its own constructor.
This third class has a function whose function header contains a reference to the base class.
This same function then tries to pass this reference to the abstract class and then .push_back() the reference into a vector of std::unique_ptr of this abstract class.
(Because I cannot directly have a vector of abstract class instances.)
My issue is that I am currently unable to get a version of this code to compile.
I have been referencing some resources online to try to solve my problem.
pass unique_ptr as an object
https://stackoverflow.com/questions/8114276/how-do-i-pass-a-unique-ptr-argument-to-a-constructor-or-a-function
adding elements of a vector of a base class
https://stackoverflow.com/questions/31410858/adding-elements-to-stdvector-of-an-abstract-class
can't access derived class method from pointer of base class - not entirely relavent, but good knowledge
https://stackoverflow.com/questions/23489554/cant-access-derived-class-method-from-pointer-of-type-base-class
I have created a shortened version of this problem in an example C++ executable that does not compile.
Here is the file:
/*
This script demonstrates my dilemma of trying to pass a subclass object
as a parameter to a function that expects the base class, and then
take that passed in object in the function and add it to a vector of that object
in a completely different class.
*/
#include <iostream>
#include <memory>
#include <vector>
class Baseclass
{
public:
Baseclass(int i)
{
lala = i;
}
// subclass MUST implement this method.
virtual int addme(int d) = 0;
protected:
int lala;
};
class Subclass : Baseclass
{
public:
Subclass(int d, int l) : Baseclass(d)
{
blahblah = l;
}
int addme(int d)
{
return blahblah + lala + d;
}
protected:
int blahblah;
};
class Mainclass
{
public:
Mainclass(uint blah)
{
anotherone = blah;
}
// This is the function I cannot seem to get to work.
// How can I make the function parameter an abstract class?
// The object being passed in is NOT abstract...
bool addController(Baseclass & basecont)
{
// This line here does NOT compile!!
// controllers.push_back(std::make_unique<What goes here?>(basecont));
return true;
}
protected:
uint anotherone;
std::vector<std::unique_ptr<Baseclass>> controllers;
};
int main(int argc , char ** argv)
{
// create subclassed controllers
Subclass cont1 = Subclass(12, 23);
Subclass cont2 = Subclass(233, 2);
// create main object
Mainclass mainbro = Mainclass(23);
// Add the subclased controllers to the main class
// THESE 2 lines do not compile!!
// mainbro.addController(cont1);
// mainbro.addController(cont2);
//
return 0;
}
I figure that I am doing something very wrong, but I do not feel the process I outlined in itself is impossible. I just think that I am going about the problem wrong.
I have highlighted, in the script, where I am not sure what I should do and where the code breaks.
I may need to take an alternative approach to the problem, I just do not know what alternatives I have available.
I see different way to fix your code, with different meaning.
Store pointers (main has ownership of the objects)
class Mainclass
{
public:
void addController(Baseclass& basecont)
{
controllers.push_back(&basecont);
}
protected:
std::vector<Baseclass*> controllers;
};
Transfer ownership
class Mainclass
{
public:
void addController(std::unique_ptr<Baseclass> basecont)
{
controllers.push_back(std::move(basecont));
}
protected:
std::vector<std::unique_ptr<Baseclass>> controllers;
};
with main:
int main()
{
auto cont1 = std::make_unique<Subclass>(12, 23);
auto cont2 = std::make_unique<Subclass>(233, 2);
Mainclass mainbro(23);
mainbro.addController(std::move(cont1));
mainbro.addController(std::move(cont2));
}
Store copies
class Mainclass
{
public:
void addController(Baseclass& basecont)
{
controllers.push_back(basecont.clone());
}
protected:
std::vector<std::unique_ptr<Baseclass>> controllers;
};
With
class Baseclass
{
// ...
public:
virtual int addme(int d) = 0;
virtual std::unique_ptr<Baseclass> clone() = 0;
};
class Subclass : Baseclass
{
// ...
public:
std::unique_ptr<Baseclass> clone() override { return std::make_unique<Subclass>(*this); }
};
Whenever you use base pointers or references with virtual methods, always add a virtual destructor:
virtual ~Baseclass() = default;
This prevents undefined behavior when the base pointers get deleted.
Next bit, use public inheritance to allow the compiler to implicitly upcast from unique_ptr<Subclass> to unique_ptr<Baseclass>:
class Subclass : public Baseclass
Your last issue is one of ownership. By having a vector of unique_ptr, you are saying that your class owns all those objects. But by declaring them on the stack in main you are saying that main owns them. Instead, use make_unique in the main routine, and transfer ownership with std::move:
bool addController(std::unique_ptr<Baseclass> basecont)
{
controllers.push_back(std::move(basecont));
return true;
}
...
auto cont1 = std::make_unique<Subclass>(12, 23);
auto cont2 = std::make_unique<Subclass>(233, 2);
// create main object
Mainclass mainbro = Mainclass(23);
mainbro.addController(std::move(cont1));
mainbro.addController(std::move(cont2));
All together:
#include <iostream>
#include <memory>
#include <vector>
class Baseclass
{
public:
Baseclass(int i)
{
lala = i;
}
virtual ~Baseclass() = default;
// subclass MUST implement this method.
virtual int addme(int d) = 0;
protected:
int lala;
};
class Subclass : public Baseclass
{
public:
Subclass(int d, int l) : Baseclass(d)
{
blahblah = l;
}
int addme(int d)
{
return blahblah + lala + d;
}
protected:
int blahblah;
};
class Mainclass
{
public:
Mainclass(uint blah)
{
anotherone = blah;
}
bool addController(std::unique_ptr<Baseclass> basecont)
{
controllers.push_back(std::move(basecont));
return true;
}
protected:
uint anotherone;
std::vector<std::unique_ptr<Baseclass>> controllers;
};
int main(int argc , char ** argv)
{
// create subclassed controllers
auto cont1 = std::make_unique<Subclass>(12, 23);
auto cont2 = std::make_unique<Subclass>(233, 2);
// create main object
Mainclass mainbro = Mainclass(23);
mainbro.addController(std::move(cont1));
mainbro.addController(std::move(cont2));
return 0;
}
Demo: https://godbolt.org/z/EyQD6S
#include <iostream>
#include <memory>
#include <vector>
class Baseclass
{
public:
Baseclass(int i)
{
lala = i;
}
// subclass MUST implement this method.
virtual int addme(int d) = 0;
protected:
int lala;
};
class Subclass : public Baseclass
{
public:
Subclass(int d, int l) : Baseclass(d)
{
blahblah = l;
}
int addme(int d)
{
return blahblah + lala + d;
}
protected:
int blahblah;
};
class Mainclass
{
public:
Mainclass(uint blah)
{
anotherone = blah;
}
// you need to make the function a template, otherwise
// you'll slice the top off the SubClass, and incorrectly
// make a copy of the base class (which you can't do,
// because BaseClass is pure virtual)
template<typename T>
bool addController(T& basecont)
{
// dont push_back new unique_ptrs, emplace_back instead!
controllers.emplace_back(new T(basecont));
return true;
}
protected:
uint anotherone;
std::vector<std::unique_ptr<Baseclass>> controllers;
};
int main(int argc , char ** argv)
{
// create subclassed controllers
Subclass cont1 = Subclass(12, 23);
Subclass cont2 = Subclass(233, 2);
// create main object
Mainclass mainbro = Mainclass(23);
// It's worth pointing out that these methods will take new copies of
// cont1 and cont2 (we don't want the mainbro instance to delete the
// memory for cont1 and cont2, since they are stack allocated)
mainbro.addController(cont1);
mainbro.addController(cont2);
//
return 0;
}
unfortunately, I can't use std::vector and have to use plain C++ arrays. I got the following code:
class Base
{
}
class DerivedCar : Base
{
public:
DerivedCar(int a) a(a) {};
private:
int a;
}
class DerivedHouse : Base
{
public:
DerivedHouse(float b) b(b) {};
private:
float b;
}
class Vector
{
Vector() :
index(0)
void add(const DerivedCar& car)
{
vec[index] = new DerivedCar(car.a);
index++;
}
void add(const DerivedHouse& house)
{
vec[index] = new DerivedHouse(house.b);
index++;
}
private:
Vector vec[100];
int index;
}
int main()
{
Vector vector;
DerivedCar car(100);
DerivedHouse house(2.f);
vector.add(car);
vector.add(house);
}
I would like to have an array of type Base and add objects of a derived type.
Is there a better approach to this other than the way I did? What would be the best way to keep copying of objects at a minimum.
How to add derived class objects to an array of base class type?
You can not put derived class objects into raw array or std::vector of base class because the derived class objects are usually larger and so simply do not fit there.
Is there a better approach to this other than the way I did?
Better approaches are certainly out there. One good example of such containers with polymorphic elements is boost::base_collection. Read its documentation and its source code. If you do not understand some detail in it then ask about that detail in Stack Overflow.
What would be the best way to keep copying of objects at a minimum.
Containers that only contain pointers to objects and intrusive containers
keep copying of objects at minimum. However such containers do not
manage the objects and so responsibility of objects life time has
to be taken by something outside.
Here is a possible way that implements a linked list:
class Base
{
};
class DerivedCar : public Base
{
public:
DerivedCar(int a) { _a = a; };
private:
int _a;
};
class DerivedHouse : public Base
{
public:
DerivedHouse(float b) { _b = b; };
private:
float _b;
};
class Object
{
public:
const Base *data;
const Object *next;
};
class Vector
{
public:
void add(const Base& v)
{
Object item;
item.data = &v;
head.next = &item;
index++;
}
private:
Object head;
int index = 0;
};
int main()
{
Vector vector;
DerivedCar car(100);
DerivedHouse house(2.f);
vector.add(car);
vector.add(house);
}
I have a class template that derives from a parent class. I am storing the children in a vector as Parent*. I can later use typeid to determine if two objects are the same type. What I want to do is compare a property of two objects that are the same type. For simplicity, I have omitted storing the objects in a vector, but the concept is demonstrated below:
#include <iostream>
#include <typeinfo>
#include <vector>
class Parent{ public: virtual ~Parent(){}};
template<typename T>
class TypedChild : public Parent
{
public:
virtual ~TypedChild(){}
T getValue() {return mValue;}
private:
T mValue;
};
int main()
{
Parent* child1 = new TypedChild<int>();
Parent* child2 = new TypedChild<float>();
std::vector<Parent*> objects;
objects.push_back(child1);
objects.push_back(child2);
if(typeid(*(objects[0])) == typeid(*(objects[1])))
if(objects[0]->getValue() == objects[1]->getValue()) // compiler error: Parent has no member named getValue
std::cout << "Success";
return 0;
}
Of course in this example I could dynamic_cast to TypedChild<int> before calling getValue(), but in the real case where the objects are in a vector I don't know their types, I just know that they are the same type so their getValue() functions should return the same type and can hence be compared.
Is there any way to do this comparison?
With your use case, being able to avoid a dynamic_cast will be hard, if not impossible. If you want to get the value of just one object, you'll need to use dynamic_cast, such as:
Parent* child = ...;
auto typedChild = dynamic_cast<TypedChild*>(child):
if ( typedChild )
{
int val = typedChild->getValue();
}
If you want to compare two objects for equality, the best case scenario is to have a virtual operator==() function.
class Parent
{
public:
virtual ~Parent(){}
virtual bool operator==(Parent const& rhs) const = 0;
};
template<typename T>
class TypedChild : public Parent
{
public:
virtual ~TypedChild(){}
T getValue() {return mValue;}
virtual bool operator==(Parent const& rhs) const
{
auto derivedRHS = dynamic_cast<TypedChild<T> const*>(&rhs);
if ( !derivedRHS )
{
return false;
}
return (this->mValue == derivedRHS->mValue);
}
private:
T mValue;
};
Code:
struct Base { ... };
struct A : public Base { ... };
struct B : public Base { ... };
struct C : public Base { ... };
Is it possible to create an array, that holds that types of struct?
sample/expected result:
Type inheritedTypesOfStruct[3] = {A, B, C};
The purpose of this is that I later want to create an object with a random class retrieved from the array.
You could create an array of functions, each of which returns a base pointer(or smart pointer) that each point to objects of your various derived classes. e.g.
typedef std::unique_ptr<Base> base_ptr;
template<typename Derived>
base_ptr CreateObject()
{
return base_ptr(new Derived);
}
int main()
{
std::function<base_ptr(void)> f[3] = {
CreateObject<A>, CreateObject<B>, CreateObject<C>
};
base_ptr arr[10];
for (int i=0; i<10; ++i)
arr[i] = f[rand()%3]();
}
Here it is in action: http://ideone.com/dg4uq
If your compiler supports RTTI, you can do something like:
const type_info *inheritedTypesOfStruct[3] = {
&typeid(A), &typeid(B), &typeid(C)
};
However, you won't be able to instantiate a class using only its type_info. The factory pattern might be a better answer to your root problem.
Update: Since type_info instances cannot be copied (their copy constructor and assignment operator are private), and arrays of references are illegal, constant pointers have to be used in the example above.
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <map>
#include <vector>
#include <memory>
using namespace std;
// interface
class Base
{
public:
virtual ~Base() { }
virtual int getClassId() = 0;
};
// class A relizes interface Base, has ID == 1 (is used in automatic registration to factory)
class A : public Base
{
public:
const static int ID = 1;
static Base* CreateInstance()
{
return new A();
}
virtual int getClassId()
{
return ID;
}
virtual ~A() { }
};
// class B relizes interface Base, has ID == 2 (is used in automatic registration to factory)
class B : public Base
{
public:
const static int ID = 2;
static Base* CreateInstance()
{
return new B();
}
virtual int getClassId()
{
return ID;
}
virtual ~B() { }
};
// this is the objects factory, with registration only (unregister s not allowed)
class ObjectFactory
{
ObjectFactory() { }
ObjectFactory(ObjectFactory&) { }
public:
virtual ~ObjectFactory() { }
static ObjectFactory& instance()
{
static ObjectFactory objectFactory;
return objectFactory;
}
typedef Base* (*Creator) ();
void registerCreator(int id, Creator creator)
{
registry[id] = creator;
}
Base* CreateById(int id)
{
return registry[id]();
}
private:
map<int, Creator> registry;
};
// this template class is used for automatic registration of object's creators
template <class T>
struct RegisterToFactory
{
RegisterToFactory(ObjectFactory& factory)
{
factory.registerCreator(T::ID, &T::CreateInstance);
}
};
namespace
{
// automaticaly register creators for each class
RegisterToFactory<A> autoregisterACreator(ObjectFactory::instance());
RegisterToFactory<B> autoregisterBCreator(ObjectFactory::instance());
}
// lets this this solution
int main(int argc, char *argv[])
{
vector<int> ids;
ids.push_back(static_cast<int>(A::ID));
ids.push_back(static_cast<int>(B::ID));
srand(time(0));
for (int i = 0; i < 20; ++i)
{
int randomClasssId = ids[rand() % ids.size()];
auto_ptr<Base> testObject(ObjectFactory::instance().CreateById(randomClasssId));
cout << "Object of classId = " << testObject->getClassId() << " has been produced by factory." << endl;
}
system("PAUSE");
return EXIT_SUCCESS;
}
I don't get the question. Are you asking for an array that can hold different type of instances at the same time? That is possible using polymorphism, of course. Or are you trying to get an array of types (like reflection)? That would be possible using RTTI or Qt type information (as an example), but I never did that.
You can take a look here: http://www.java2s.com/Code/Cpp/Class/Objectarraypolymorphism.htm
on how to use Polymorphism in C++.
Shape.h
namespace Graphics {
class Shape {
public:
virtual void Render(Point point) {};
};
}
Rect.h
namespace Graphics {
class Rect : public Shape {
public:
Rect(float x, float y);
Rect();
void setSize(float x, float y);
virtual void Render(Point point);
private:
float sizeX;
float sizeY;
};
}
struct ShapePointPair {
Shape shape;
Point location;
};
Used like this:
std::vector<Graphics::ShapePointPair> theShapes = theSurface.getList();
for(int i = 0; i < theShapes.size(); i++) {
theShapes[i].shape.Render(theShapes[i].location);
}
This code ends up calling Shape::Render and not Rect::Render
I'm assuming this is because it is casting the Rect to a Shape, but I don't have any idea how to stop it doing this. I'm trying to let each shape control how it is rendered by overriding the Render method.
Any ideas on how to achieve this?
Here's your problem:
struct ShapePointPair {
Shape shape;
Point location;
};
You are storing a Shape. You should be storing a Shape *, or a shared_ptr<Shape> or something. But not a Shape; C++ is not Java.
When you assign a Rect to the Shape, only the Shape part is being copied (this is object slicing).
This problem is called slicing - you lose the derived functionality when copying to a base.
To avoid this use pointers to the base class, i.e.
std::vector<Graphics::Shape*> s;
s.push_back(&some_rect);
The problem is that in your vector you are storing copies of Shape objects, and copying a Shape object does not copy the data or functionality of its derived classes - you're slicing the polymorphism away.
Manage the objects using new and delete, and arrange for your vector to store pointers to them.
The polymorphism will only work from a pointer to a shape, not from a shape object.
You are accessing the shape object directly for the override to work you need to access the object via a pointer or references.
For example when you assigne the Shape into the ShapePointPair the code will 'slice' the object and only copy the Shape bit into the ShapePointPair
Doing this will mean you have to watch memory management - so you could use a smart pointer in the struct
ShapePointPair {
smart_pointer shape;
Point location;
};
No, it is not casting.
You can instead store a reference to baseclass Point:
struct ShapePointPair {
Shape shape;
Point &location;
};
This reference must be set at construction time for struct
ShapePointPair. Add a constructor to ShapePointPair for this
purpose. It must be passed (newly created) instances of
Rect.
Also observe the memory management responsiblities (proper
written destructors, etc.).
You could try boost::ptr_vector
http://www.boost.org/doc/libs/1_40_0/libs/ptr_container/doc/ptr_container.html
I'm not sure to explain well because of my english is poor.
I think you should have to use it reference or pointer type.
because shape is exactly defined what it has to do.
If you use your code directly, your child try to copy and do shape's working.
That is why doesn't work your override function.
use pointer or reference
like this.
pointer.h
class Parent {
public:
virtual void work() { printf("parent is working now\n"); }
};
class Child1 {
public:
virtual void work() { printf("child1 is working now\n"); }
};
class Child2 {
public:
virtual void work() { printf("child2 is working now\n"); }
};
struct Holder {
Parent* obj1;
Parent* obj2;
};
int main() {
Child1 child1;
Child2 child2;
Holder holder = { &child1, &child2 };
holder.obj1->work();
holder.obj2->work();
return 0;
}
reference.h
class Parent {
public:
virtual void work() { printf("parent is working now\n"); }
};
class Child1 {
public:
virtual void work() { printf("child1 is working now\n"); }
};
class Child2 {
public:
virtual void work() { printf("child2 is working now\n"); }
};
struct Holder {
Parent& obj1;
Parent& obj2;
};
int main() {
Child1 child1;
Child2 child2;
Holder holder = { child1, child2 };
holder.obj1.work();
holder.obj2.work();
return 0;
}
*ps: personally i use abstract function(virtual void something() = 0;).
because i also forgot about it sometimes so i catch it as syntax error.