So here is the deal, I think I need to go another route regarding the pattern I am using but I thought I would get some expert opinions first.
I have a class (UsingClass) that maintains a dynamic list of Base class pointers. When adding a new object to the list I have to figure out what type of object it is because I can't really make it work in a polymorphic manner. The line below tagged "THIS WILL NOT WORK LIKE I WANT IT TO!!" would ideally polymorphically use the =operator from the Derived class of interest, but unfortunately it only uses the default =operator for the Base class.... probably would work if I made Base pure virtual (basically confine it use to an interface with no data members of its own), but I don't really want to have the Derived classes hold members that are common between both (maybe I need to just cut bait and do it).
I think I may just completely be using the wrong pattern but I don't know what alternatives I should consider.
I know the code does not necessarily compile but please work with me. Thanks in advance!
//code block
class Base {
protected:
int x;
float y;
string type; // default to Derived1 or Dervied2 depending on the object inst
public:
virtual int functionM(int l) = 0;
int functionN(int P);
};
class Derived1 : public Base {
protected:
int a;
public:
int functionM(int l);
float functionR(int h);
};
class Derived2 : public Base {
protected:
int b;
float r;
public:
int functionM(int l);
float functionR(int h);
};
#define MAX_ARRAYSIZE 10
class UsingClass {
private:
Base* myDerived1And2DynamicList[MAX_ARRAYSIZE];
int indexForDynamicList;
public:
void functionAddDerivedToList(*Base myInputPtr) {
if((indexForDyanmicList + 1) < MAX_ARRAYSIZE) {
if(myInputPtr->type == "Derived1") {
myDerived1And2DynamicList[indexForDyanmicList+1] = new Derived1;
*myDerived1And2DynamicList[indexForDyanmicList+1] = *myInputPtr; // THIS WILL NOT WORK LIKE I WANT IT TO!!
} else if (myInputPtr->type == "Derived2") {
myDerived1And2DynamicList[indexForDyanmicList+1] = new Derived2;
*myDerived1And2DynamicList[indexForDyanmicList+1] = *myInputPtr; // THIS WILL NOT WORK LIKE I WANT IT TO!!
}
}
} // end of void function
};
Rather than checking the type you could simply add a virtual function to the class 'Base' and call that. This would simplify void functionAddDerivedToList(*Base myInputPtr) to the following:
void functionAddDerivedToList(*Base myInputPtr)
{
if((indexForDyanmicList + 1) < MAX_ARRAYSIZE) {
myDerived1And2DynamicList[indexForDyanmicList+1] = myInputPtr->clone();
}
}
Clone would always be implemented to call the class's copy constructor. So in Base, add the following:
virtual Base* clone() = 0;
The implementation would always take this form (example is for Derived1, a subclass of Base in your example):
virtual Base* clone() { return new Derived1(*this); }
One problem I see is that you are sing C-style array to contain a list of "Base" objects. Note that the size of the elements in the array in this case will be the sizof(Base), which is different with sizeof(Derived1) and sizeof(Derived2). Both derives may be different as well. What you can do in this case is to have the array contain pointers of Base objects instead of the actual objects. That will make the size uniformed to 4 bytes and you can access the objects in your array as pointers. Because the array now contain pointers you do not have to determine the type if you simply want to insert them in the array.
void functionAddDerivedToList(Base* myInputPtr)
{
if((indexForDyanmicList + 1) < MAX_ARRAYSIZE)
myDerived1And2DynamicList[indexForDyanmicList+1] = myInputPtr;
}
If you want to access the object from the array you can do something like this.
Base* p = myDerived1And2DynamicList[index];
p->MyMethod();
You can trust that the correct MyMethod function will be called based on the actual type of p in this case.
I have a class (UsingClass) that maintains a dynamic list of Base class pointers.
Sorry, but you have not (wrong syntax). But don't go that way.
First, give your Base class a virtual destructor. Otherwise you will experience memory leaks.
Then, redesign your UsingClass container. Give it a vector of shared_pointer to Base member to hold dynamically alocated polymorphic objects. (If you use a non C++0x-compiler, you can use std::tr1::shared_ptr.)
class UsingClass {
private:
std::vector<std::shared_ptr<Base> myList;
// int indexForDynamicList; is now myList.size()
public:
void Add(Base* myInputPtr) {
myList.push_back(myInputptr);
}
// ...
};
To add polymorphic objects, use
UsingClass container;
container.add(new Base);
container.add(new Derived1);
container.add(new Derived2);
You can call all polymorphic methods by iterating
for (size_t i = 0; i < myList.size(); ++i)
{
myList->functionM(); // give the function a more "speaking" name
}
By using shared_ptr you can hold many pointers to one object and don't have to care about freeing memory. Copying the pointers will not copy objects (so called shallow copy). If you really need to copy objects also (so called deep copy), your Base and derived classes will have to implement a virtual clone() method.
Related
So I am quite confused about copy constructors in C++. I have the following code:
class creature /* abstract class*/
{
private:
string name;
int longevity;
creature_society * cs;
public:
creature(int,int,int,creature_society*);
//creature(const creature&);
virtual ~creature();
virtual int is_a_good() =0;
};
class good_creature : public creature
{
public:
good_creature(int,int,creature_society*);
//good_creature(const good_creature&);
~good_creature();
int is_a_good() //returns 1
};
class bad_creature : public creature
{
public:
bad_creature(int,int,creature_society*);
//bad_creature(const bad_creature&);
~bad_creature();
int is_a_good(void); //returns 0
}
So I have an abstract class called creature , a good_creature and a bad_creature which are a children class of creature .
At my program I also have an array called society which has type of creature* objects. If my creature through a condition is defined as good, I allocate space for it and store it in society array as good_creature. The same happens for bad creature. I construct it as described in the following code:
society = new creature*[M];
for(i=0;i<M;i++)
{
if(condition)
society[i] = new good_creature(L,good,this);
else
society[i] = new bad_creature(L,bad,this);
}
So I have to make a pure virtual function: creature::clone(int position) which if it's either a good_creature or a bad_creature, it has to delete the society[pos] and make a copy of the society[pos-1] through a copy constructor.
So for example my good_creature::clone(int position) is like this:
void good_creature::clone(int position)
{
int cop_pos=position -1; //getting the position before that in order to copy it
delete society[pos];
society[pos] = new good_creature( *society[cop_pos] );
//....
}
I get an error because society[cop_pos] is of type creature*. I tried casting it to good creature but unfortunately I keep getting errors. Is it because I am not calling the copy constructor right, is it because I am not casting right? Any ideas? This has been buffling me for 2 days. Keep in mind I' m a newbie and might have done something wrong.
Also I don't need to define my own copy constructor since all the elements in society[i] point at the same object that is defined by creature_society * cs, so I'm trying to use the default constructors since I do not need deep copy.
Thanks for your time.
UPDATE
A class I forgot to mention and the way I construct society
class creature_society
{
private:
int N; // number of the creatures we want to be made in society
creature ** society;
public:
creature_society(int,int);
~creature_society();
};
You don't know if society[cop_pos] is the correct type, so you cannot safely cast. A better solution is to use a virtual function to create a copy
class creature {
public:
virtual creature* clone() const = 0;
...
};
class good_creature {
public:
good_creature* clone() { return new good_creature(*this); }
...
};
//Similar for bad_creature (and any other derived classes)
In your case you'd call it like this:
society[pos] = society[cur_pos]->clone();
There's no need to know the type of the object you're cloning. The virtual function call takes care of that for you. Note that good_creature::clone returns a good_creature* instead of a creature*. This is a valid overload. A virtual function overload is allowed to return a derived class. In this case you could have it return a creature* as well.
Use polymorphism and virtual dispatch to do the work for you.
Define a clone virtual function in creature class.
class creature
{
virtual creature * clone() = 0;
}
and then override it in children:
class good_creature: public creature
{
virtual creature * clone() override
{
return new good_creature(*this);
}
}
and similar for bad_creature.
Then use it:
society[pos] = society[pos - 1]->clone();
Side note: your design seems to influenced by languages like Java. This is not a (modern) C++-style. For example, in modern C++ ownership is better expressed by unique_ptr instead of pointers. This would make code cleaner and much safer.
The problem is that society is an array of creature, not of good creature, so the copy constructor doesn't apply.
You can define a constructor for good_creature and for bad_creature taking as argument a creature:
good_creature(const creature&);
This is something that has been frustrating me for over a week. I have gone through various threads on dynamic_casting on this website but I am still not sure what the best way to implement this is.
So I have a base class like this:
class baseClass
{
public:
class recordBase
{
public:
virtual ~recordBase(){}
};
virtual ~baseClass() {};
virtual bool Allocate( int size,
recordBase *outRecord) = 0 ;
virtual bool Free(recordBase *allocRecord) = 0;
} ;
This has two derived classes.
A derived class A like so..
class DerivedA : public baseClass
{
public:
class derivedRecordA : public baseClass::recordBase
{
public:
inline ~derivedRecordA(){} ;
someClass *obj1 ;
}
bool Allocate(int size,
baseClass::recordBase *outRecord);
bool Free(baseClass::recordBase *allocRecord) ;
}
I have a similar derived class 'DerivedB' that has its own implementation of a dervied recordBase and Allocate and Free functions.
Now Finally I have a class C that uses the above baseClass.
class C
{
public:
baseClass *allocator ;
Allocate(int size) ;
Free(void) ;
}
now here is my issue, based on some conditions class C either stores an allocator which is derivedA or stores one that is derivedB .
The allocate function for class C looks like this
C::Allocate(int size)
{
//condition where DerivedA is needed
DerivedA::derivedRecordA recObj ;
if(allocator->Allocate(size, &recObj))
{
return true;
}
else return false ;
}
Now the problem is I am forced to use dynamic casting within the DerivedA::Allocate implementation like so:
DerivedA::Allocate(int size, baseClass:recordBase *outRecord)
{
DerivedA::derivedRecordA *rec = dynamic_cast< DerivedA::derivedRecordA *>(outRecord) ;
//allocate mem and store info in 'rec'
return true ;
}
How do I avoid using dynamic_casting here. Is there a cleaner solution to this problem ?
There is a problem with your base class design which is why you are having implementation issues at the derived level.
If I have a pointer to a baseClass instance (whatever actual type it must be), then the implied contract of the Allocate method is that I can pass in a pointer to any kind of baseClass::recordBase and things should work.
If the derived classes override the function then they should not narrow the function requirements for users of the function. This would effectively mean that they are providing an override that doesn't satisfy the interface of the base class function. If they need to to this then they should provide a different function with a suitable interface.
Having said that, I would have expected an Allocate function to allocate a new object. In this case you can override and return a pointer to a specialization (this is known as a covariant return type). E.g., you can override:
virtual recordBase* Allocate(int size) = 0;
with
virtual derivedRecordA* Allocate(int size);
provided that size isn't supposed to be an array size and you are not trying to return a pointer to an array of derived objects which, again, would be problematic for users of the base class interface.
You really need to expand your question with what the contract and expected behaviour of your base class functions and there overrides are supposed to be to elicit better answers.
There is a cleaner solution, which is using a virtual function on baseRecord which is suitably overridden.
If that does not please, checking for typeid and using static_cast on success might be faster than dynamic_cast, even if it is bad coupling.
i am pretty sure this is a simple question for a long time c++ user, this should be a pattern or the problem should be solved in any other way but given i am Python developer and a total novice with c++ i don't know how it's usually done.
Suppose that i have a class where i want to store a pointer to an object that can be of 1 of two different classes that respects an interface, for example:
class AllPlayers
{
public:
virtual void play();
};
class VlcPlayer: public AllPlayers
{
public:
virtual void play();
};
class Mplayer: public AllPlayers
{
public:
virtual void play();
};
class MyMediaPlayer
{
public:
MyMediaPLayer(int playerType);
AllPlayers m_player;
};
MyMediaPlayer::MyMediaPlayer(int PlayerType)
{
if (PlayerType == 0) {
VlcPlayer tmp_player;
m_player = static_cast<AllPlayers> (tmp_player);
}
else {
Mplayer tmp_player;
m_player = static_cast<AllPlayers> (tmp_player);
}
}
MyMediaPlayer test(0);
test.play();
First, i know this would not work and that it seems pretty normal why but how could i get this effect? i would like to have a member of a class for what i am going to use ever the same methods, implemented using a interface and i would like to avoid trying to cast to every of the derived classes every time i am going to use one of his methods.
C++ is value-based, i.e., if you create an object of a given type you really have an object of this type. This doesn't play nicely with dynamic polymorphism. To get dynamic polymorphism you use a pointer or a reference to the actual object. To also get the life-time straight you typicslly allocate the corresponding object on the stack (make sure your base class has a virtual destructor if you ever release an object of a derived type using a pointer to the base). With this, you should be all set: just call a virtual function of the base class through a pointer to rhe base: When you overridethe function in the derived class this is the function which is called.
If you write
AllPlayers m_player;
that is going to be an instance of AllPlayers and cannot be an instance of a class that derives from it.
You should instead use a pointer and allocate the class on the stack.
For example:
class MyMediaPlayer
{
public:
MyMediaPLayer(int playerType);
~MyMediaPLayer();
AllPlayers m_player;
};
MyMediaPlayer::MyMediaPlayer(int PlayerType)
{
if (PlayerType == 0) {
m_player = new VlcPlayer;
}
else {
m_player = new Mplayer;
}
}
MyMediaPlayer::~MyMediaPlayer()
{
if (0 != m_player) {
delete m_player;
m_player = 0;
}
}
As suggested by #xception use of unique_ptr may relieve you from having to write code to deallocate the instance.
As correctly pointed out by #DietmarKühl you should always declare a virtual destructor in a root class (a base class that does not itself derives from some other class) as is the case with AllPlayers.
class AllPlayers
{
public:
virtual ~AllPlayers();
virtual void play(); // note: this should probably be pure virtual.
};
The reason this will not work is colloquially known as Object Splicing. (Or, for those Harry Potter readers out there, Object Splinching)
Let's look at an example:
class Foo
{
public:
int bob;
float fred;
// Foo(const Foo& otherfoo); // implicit copy constructor
};
class Bar : public Foo
{
public:
double gabe; // gabe newell is fat
char steve; // steve jobs is thin
// Bar(const Bar& otherbar); // implicit copy constructor
};
int main()
{
Foo f;
Bar b;
f.bob = 10;
f.fred = 1.5;
b.bob = 15;
b.fred = 2.5;
b.gabe = 1.77245385091; // sqrt(pi)
b.steve = -4;
f = Foo(b);
return 0;
}
This is legal and valid. Problem is, the implicit copy constructor of Foo is called, and Foo's copy constructor knows nothing about what a Bar is. Only that it contains everything a Foo has, and some extra irrelevant crap. Because of this, only the Foo's data gets preserved; the data unique to the Bar gets spliced off.
It's important to note that this is DEFINED BEHAVIOR: it's doing EXACTLY WHAT YOU TELL IT TO. Casting between a subclass of a base class and a base class is implicit. Furthermore, the behavior of the copy constructor is implicit.
It's also important to note that, under the hood, C++ pointers and references work in the same way. It's perfectly sane to pass the Bar to Foo's copy constructor by reference, this pass by reference does not produce a copy of the object. It's the same as working with a pointer.
The actual splicing takes place as a direct result of the copy constructor biting off more than it can chew. It gets an object with more state than it expected, and its only choice is to ignore the extra state.
With python, this doesn't happen because everything is implicitly stored as a reference type. Since you only work with references (the objects themselves are abstracted away), you never have the opportunity to accidentally splice an object.
This is probably best shown with example code. The following fails to compile with g++:
struct Base {
};
struct Derived : public Base {
};
struct Container {
Derived data_;
};
int main(void) {
Base Container::*ptr = &Container::data_;
}
I get the following error: invalid conversion from 'Derived Container::*' to Base Container::*'.
Is this not allowed by the language? Is this a compiler bug? Am I using the wrong syntax?
Please help!
Some background as to why I'm trying to do this: I have several member data pieces that I want to use primarily as their derived types, but I want to be able to populate them through some common code. Data will be coming in an arbitrary order and have a string label that I would use to select the appropriate member data to populate. I was planning on creating a std::map<std::string, Base Container::*> to assign data to each member through a common interface. I'd like to avoid have a giant if else construct to find the right member data.
This is not a compiler bug, you can't do that. (But you can assign a Base::* to a Derived::*).
I don't see any good reason for the limitation (excepted that to handle the case of multiple inheritance, that would complicate even more the representation of a member pointer).
There are a lot of fairly complex, some not-well-explained, and a few flat wrong answers in this thread.
But the problem, it seems to me, is that there simply isn't a Base member within Container -- there is a Derived member. You can't do this:
Base Container::*ptr = &Container::data_;
...for the same reason you can't do this:
int a;
long* pl = &a;
In the second example, the object isn't a long, it's an int. Similarly, in the first example the object isn't a Base, it's a Derived.
As a possibly tangential point, it seems to me like what you really want to do is have Base be an abstract class, and have Container have a Base* rather than a Derived member.
Pointers to members in C++ are not really pointers but more like offsets to given member and are specific to the type, so what you are trying to do is not really supported.
Here's a decent discussion here on Stackoverflow C++: Pointer to class data member.
You just need to write:
Base* ptr = &container.data_;
but container has to be an instance of Container, so you have to create one variable of that type somewhere.
You cannot convert C::*A to C::*B even if there is a conversion possible between A and B.
However, you can do this:
struct Base
{
virtual ~Base() {}
virtual void foo() { std::cout << "Base::foo()\n"; }
};
struct Derived : Base
{
void foo() { std::cout << "Derived::foo()\n"; }
};
struct Bar
{
Base* x;
Bar() : x(new Derived) {}
};
int main()
{
Bar b;
Base* Bar::*p = &Bar::x;
(b.*p)->foo();
}
You would have to static_cast to do this conversion as seen in 5.3.9/9. This reason for this is that it acts as a static_cast from parent object pointer to child object pointer would. In other words, putting a pointer to a derived member into a pointer-to-parent-member would allow you to possibly access a non-existent derived member from a parent object or pointer. If the standard allowed this automatically it would be easy to mess up and try to access a child member on a class that isn't of the appropriate child type (that contains said member).
Without more information it sounds like you need a different/better constructor/set interface in your Base class rather than trying to use pointers-to-member here.
I think what you want is a 'container', ie a struct which just has pointers:
struct Container{
Base* derivedAdata_;
Base* derivedBdata_;
...
};
Now each of the members you know to be of a specific type (ie DerivedA, DerivedB etc) so you can down-cast them later.
But first you are receiving data (in arbitrary order), but with a string name, so you should have a map:
std::map<std::string, Base* Container::*>
And you must have already populated the map:
myMap["DerivedA"] = &Container::derivedAdata;
...
Now data arrives and you start populating the container:
instance.*(myMap[key]) = factory(key, data);
myMap[key] picks the right member of the container and factory(key,data) creates instances.
btw you could just have a map as your container anyway:std::map<std::string, Base*>
Regarding the original issue, you can do this using pointer to functions, instead of introducing base classes.
class Container {
public:
void set(std::string const& label, std::string const& value);
void setName(std::string const& value) { _name = value; }
void setAge(std::string const& age) {
_age = boost::lexical_cast<size_t>(age);
}
private:
std::string _name;
size_t _age;
};
How to implement set then ?
// container.cpp
typedef void (Container::*SetterType)(std::string const&);
typedef std::map<std::string, SetterType> SettersMapType;
SettersMapType SettersMap =
boost::assign::map_list_of("name", &Container::setName)
("age", &Container::setAge);
void Container::set(std::string const& label, std::string const& value) {
SettersMapType::const_iterator it = SettersMap.find(label);
if (it == SettersMap.end()) { throw UnknownLabel(label); }
SetterType setter = it->second;
(this->*setter)(value);
}
struct Container {
Derived data_;
};
int main(void)
{
Base Container::*ptr = &Container::data_;
}
The first problem is that Container doesn't have a member called ptr
Container container_object;
Base *ptr = container_object.data_;
Would work. Note that there needs to be a container object to create the data_ member and it would need to be made public.
The alternative would be for derived::data_ to be a static member.
I have two classes:
class Object {
public:
Object();
virtual void update();
virtual void draw();
private:
protected:
int x, y, tick;
}
and
class Unit : public Object {
public:
Unit();
void update();
private:
protected:
}
I then define the constructors and functions in sepparate .cpp files.
Here's the definitions for Object:
Object::Object() {
x = y = 0;
};
Object::update() {
tick ++;
};
Object::draw() {
// All my draw code is in here.
};
And Unit:
Unit::Unit() : Object() {
};
Unit::update() {
Object::update();
// Then there's a bunch of movement related code here.
};
Everything works fine individually, but I run into a problem when trying to call functions from within a vector.
vector<Object> objects;
I then do this in my void main():
for (int i = 0; i < objects.size(); i ++) {
objects[i].update();
objects[i].draw();
};
This draws everything fine, but it only calls the Object verson of update() not the version as defined by the derived class. Do I have to make a vector for each type that I derive from the Object class for it to work, or is there another way to call the derived functions?
Thanks in advance - Seymore
Yes, it calls methods of class Object, because you have a vector of class Object objects:
vector<Object> objects; // stores instances of class Object
The possible solution is to use a vector of pointers:
vector<Object*> objects;
objects.push_back( new Unit() );
and then call though pointers:
for (int i = 0; i < objects.size(); i ++) {
objects[i]->update();
objects[i]->draw();
}
If you want to use object oriented polymorphism in C++ (with the meaning : you have a base class and derived classes and at runtime you can come across any off those) you must use pointers.
vector<Object *> objects;
That means manual memory management (but you can use shared_pointers or http://www.boost.org/doc/libs/1_35_0/libs/ptr_container/doc/ptr_container.html), and possibly a very slight loss of performance (because of one extra dereferencing and v-table, however you shouldn't really care about it). And don't forget to make your methods virtual ;)
I think this is why I rarely use on my daily work object oriented programming as I learned it at school ;) I use heritage, but don't mix mother and daugther classes in the same containers (and I use templates for many interfaces).