I am trying to create a vector of derived objects from within their base class.
class Animal
{
// Do Stuff
}
class Dog : public Animal
{
// Do Stuff
}
class AnimalKingdom
{
vector<Animal> animals;
vector<Dog> getDogs();
}
vector<Dog> AnimalKingdom::getDogs();
{
vector<Dog*> dogs;
for(i = 0; i < animals.size(); i++)
{
Animal& a = *animals[i];
if(typeid(a).name() == "class Dog")
{
dogs.push_back(*a);
}
}
}
But obviously *a isn't a pointer to a dog so it can't be added to dogs?
Does that make sense?
You need to type cast Animal into a Dog. Do some reading on what static_cast and dynamic_cast are. But generally static_cast is if you know what type you are converting to, and dynamic_cast is a guess and will return null if it not that type.
for(i = 0; i < animals.size(); i++)
{
Animal* a = &animals[i];
if(typeid(a).name() == "class Dog")
{
dogs.push_back(static_cast<Dog>(a));
}
}
Ps.Im at work so I cant check that code, looks rightish tho =D
First, typeid(a).name() will return a string that is compiler specific. In my gcc, for example, the returned string would be something totally different. Also, think of a third class that is subclass of Dog. Your typeid(a).name() would give you "class Chihuahua", which is a dog, but is not "class Dog".
You should use dynamic_cast for querying object type. When you do dynamic_cast<Dog*>(a) you are asking "can a be correctly casted to Dog?". If yes, you will have a pointer of type Dog*, if not you will have a NULL pointer.
Finally, at class AnimalKingdom , your vector is not going to allow you to have objects of type Dog. When you create a std::vector<Animal>, you are creating a vector whose elements are of fixed type sizeof(Animal). What you need is to work with pointers. A pointer points to a memory address without forcing this address to be of any size or of the base class.
Just to make it a bit more clear: When you do Animal a; you are creating a variable that is of the type Animal and has size sizeof(Animal). When you do Animal* a you are creating an memory address that has the size 4 bytes (or 8 bytes), for any pointer this will have this size. So it is possible that the Animal* points to something different than Animal, it may point to a subclass of Animal.
This is the difference between static allocation (fixed size) and dynamic allocation (dynamic size, but note that the pointer has a fixed size).
Your main problem is to understand you can not up-cast, This yields null. you can downcast the dog into animal and use only the min attributes of the parent though,
So this problem can be easily solved like:
1- return vector and use polymorphic flow to do whatever you want later.
2- make some bool or int to check or mark the kind of animal as below. e.g. make it 2 for dogs, This variable is defined in animal class. then use virtual functions to dynamically go to whatever you want at run time. so the below code can be good skeleton for you.
class Animal
{
int type;
virtual void setType()=0;
virtual int getType()=0;
};
class Dog :public Animal
{
void setType()
{
type = 2;
}
int gettype()
{
return type;
}
};
Have fun.
Related
I made a toy example of a problem I'm facing with my code:
I have an animal which I don't know what will be after a later stage, so I initialize it to a generic animal.
But later on, I want to make it a cat, so I'm assigning myAnimal to be a Cat
#include <iostream>
class Animal {
public:
int weight;
virtual void Sound() {
// To be implemented by child class
}
};
class Cat : public Animal {
public:
void Sound() {
std::cout << "Miau" << std::endl;
}
// Only cats purr
void Purr() {
std::cout << "Purr" << std::endl;
}
};
int main() {
// At this point I don't know which animal I'll have, so I initialize it
// to a generic Animal
Animal* myAnimal;
animal->weight = 10;
// At this point of the code, I know what animal I want, so I assign animal
// to be a Cat
double selectedAnimal = 0;
if (selectedAnimal == 0) {
myAnimal = &Cat();
// myAnimal = new Cat(); // this will just create a new Cat, losing
// the already assigned weight.
// I want to "upgrade" my generic animal, keeping its properties and adding
// new ones specific to cats
}
myAnimal->Sound();
myAnimal->Purr(); // ERROR: Class Animal has no member Purr
return 0;
}
I think I'm not assigning correctly myAnimal to be a Cat, but it is still an Animal. Howver the compiler doesn't complain when I do myAnimal = &Cat();.
So I don't understand if the compiler allows me to assign Animal to the class Cat myAnimal = &Cat(); why it complains when I try to use a method specific of the class Cat.
How should I reassign my generic animal in such a way that is now a full Cat with all its methods?
EDIT:
Answering some comments:
-Animal should not have a Purr method, only cats purr.
-I don't know at compile time what Animal will I have, that's why I assign it to be generic at the beginning.
I can reassign myAnimal to be a new Cat, but then any variables already set to the generic animal will be lost (eg: Animal might have a weight variable already set before knowing it's a Cat)
I'll try the suggested down-casting by #Some programmer dude
Firstly, when creating the Cat ensure that you allocate the memory correctly. Currently you are taking the address of a temporary object i.e. &Cat() which is not valid C++.
You can do this in two different ways:
// On the stack
Cat cat;
myAnimal = &cat;
// OR
myAnimal = new Cat(); // On the heap (remember to free the cat)
Then, when you want to use the animal as a cat, you can use a downcast e.g.:
auto myCatPtr = dynamic_cast<Cat*>(myAnimal);
if (myCatPtr) {
// This means the pointer is valid
myCatPtr->Purr();
}
Here is a working example.
The answer from Matthias GrĂ¼n shows how to manipulate C++ to do what you want.
However, my advice is to stop making C++ do what you think is right, and do it the way C++ wants to do it.
C++ wants you to never throw the type of an object away. It is a strongly-typed language. It almost always an "anti-pattern" to throw away the type of an object.
One common technique for avoiding this anti-pattern, is to separate "ownership" from "use". You can use a pointer to unknown-type, easily. Owning an object by a pointer to unknown type is really hard.
int main()
{
Cat my_cat;
Animal* any_animal = &my_cat; // non-owning pointer.
any_animal->Sound();
my_cat.Purr();
}
All that myAnimal = &Cat(); does is create a temporary of type Cat and assign the address of it to myAnimal, leaving you with a dangling pointer. myAnimal will point to an invalid address afterwards.
Also, even if it had been correctly assigned, for example by writing
myAnimal = new Cat{};
it would still require a cast so the compiler knows that it's dealing with a Cat, for example like so:
auto pCatInstance = dynamic_cast<Cat*>(myAnimal);
if (pCatInstance != nullptr)
pCatInstance->Purr();
So, I'm on the last chapter of Programming for Games Module 1/2 and I ran into the code I've got below. I understand pointers are being created, I understand the first line of code, I pretty much understand what upcasting and downcasting are in concept, but I don't understand, specifically, what (Base*) and (Derived*) are doing here (the right hand sides of each line minus the first are confusing me).
Can someone just explain to me what this syntax is doing?
int main()
{
Derived* derived = new Derived();
Base* base = (Base*) derived; //upcast
Derived* derived2 = (Derived*) base; //downcast
return 0;
}
Consider the following statement:
int a = (int)(3.14);
This is called explicit type-casting. You basically tell the compiler, "I want to cast the float value 3.14 to an integer" which results in truncation of the decimal part and you get the value 3 i.e. the float value 3.14 is casted to an integer value 3. The compiler can perform such type-casting implicitly for fundamental data types.
Now consider the following:
Derived* derived = new Derived();
This creates a pointer of type Derived and dynamically allocates a new object of type Derived to it.
Now, the syntax:
Base* base = (Base*) derived;
This syntax is not really required as C++ allows that a derived class pointer (or reference) to be treated as base class pointer i.e. upcasting, but not the other way around as downcasting is a potentially dangerous operation.
The syntax however explicitly tells the compiler "I want to create a pointer of type Base and assign to it, the derived pointer which I have already created. Before assigning the value, I want to cast the type of pointer derived from type Derived to type Base and then assign it to base."
Please note that casting does not convert the type of pointer derived. The syntax above does not convert the type of pointer derived to Base. It only casts it into a Base pointer before assigning the value to base.
Similarly for the third line.
This is type-casting in C-Style. Although C++ supports C-Style type-casting, we have operators like static_cast, dynamic_cast etc in C++ which do a much better job. If you are wondering why we need such operators here is an excellent explanation :
Why use static_cast<int>(x) instead of (int)x?
Hope this clarifies your confusion.
Let's do an example. We have the following construction:
class Animal
{
public:
virtual string sound() = 0;
virtual ~Animal() {}
};
class Pig: public Animal
{
public:
string sound() override { return "Oink!"; }
};
class Cow : public Animal
{
public:
int milk; // made this public for easy code, but probably should be encapsulated
Cow() : milk(5) {}
string sound() override { return "M" + string(milk, 'o') + "!"; } // a Moo! with milk times many Os
};
What we now want to do is to store a list of animals. We can't use vector<Animal> because that would contain instances of the class Animal, which is purely abstract - Animal::sound is not defined.
However, we can use a vector of pointers:
vector<Animal*> animals;
animals.push_back(new Cow);
animals.push_back(new Pig);
animals.push_back(new Cow);
for(Animal* animal : animals)
{
cout << animal->sound() << endl;
}
So far, so good. But now take a look at the class Cow, there is the member milk which has an influence on the output. But how do we access it? We know that the first and third entries in animals are of type Cow, but can we use it? Let's try:
animals[0]->milk = 3;
This yields:
error: 'class Animal' has no member named 'milk'
However, we can do this:
Cow* cow = (Cow*) animals[0];
cow->milk = 3;
for(Animal* animal : animals)
{
cout << animal->sound() << endl;
}
What we done here is to create a pointer to Cow from a pointer to Animal of which we knew that it was actually pointing to an object of type Cow.
Note that this is risky - here, we knew that the first entry in the vector is of that type, but in general, you don't. Therefore, I recommend that you use safe casting, that is especially dynamic_cast. If you come to understood pointer casting and feel safe in that topic, read some tutorial on how to use dynamic_cast.
Right now, we have cast the base class to the derived class, but we can also do the opposite:
Cow* cow = new Cow;
cow->milk = 7;
animals.push_back((Animal*) cow);
for(Animal* animal : animals)
{
cout << animal->sound() << endl;
}
I assembled all of this into http://www.cpp.sh/6i6l4 if you want to see it in work.
Hope that this gives you a better understanding of what we need this for. Storing a list with objects of different types but a common base class is quite usual, and likewise is pointer to unknown subtypes. If you want more practical examples, ask. Thought about providing one, but don't want to overwhelm you for the start.
(Lastly, we need to clean up our memory, as we put our variables in the heap:
for(Animal* animal : animals)
{
delete animal;
}
animals.clear();
if we wouldn't do it, we'd have a memory leak. Better would have been to use smart pointers like shared_ptr - again here the recommendation to read into that when you feel safe in the base topic.)
I have an interface, let's call it Creature, who has virtual functions that cause it to be abstract.
I have child classes of this interface such as Dog, Cat, and Pig.
The compiler doesn't seem to like the following line due to not being able to declare variable thing to be of abstract type Creature.
Creature thing = Dog();
I know I can't instantiate interfaces and the like, but this is just a Dog being declared as a Creature.
I need some way of having one declaration work for all the children (i.e., being able to put Dog(), Cat(), or Pig() where Dog() is in the line above).
Can this be done in c++ or am I misusing inheritance and interfaces completely?
Object types themselves are not polymorphic in C++. The line you've given declares a Creature object and then attempts to initialise it with a Dog object. If Creature weren't abstract, this would result in slicing - thing wouldn't be a Dog any more, it would just be a Creature. Since it is abstract, you simply can't have a Creature object anyway.
You need to use pointers or references for polymorphic behaviour. Consider for example:
Creature* thing = new Dog();
You can now dereference thing and use it as a Creature, even though it's dynamic type is Dog. However, using raw pointers like this is usually not recommended, as you have to manually ensure that the object is deleted at some point. The ownership can become confusing. Your best bet is to put it in a smart pointer, such as:
std::unique_ptr<Creature> thing(new Dog()); // or std::make_unique when we have it
Here, I've demonstrated std::unique_ptr, but the choice of smart pointer will depend on the ownership semantics for that object. A common alternative is std::shared_ptr.
To demonstrate polymorphism with references:
Dog dog;
Creature& thing = dog;
// Can now use dog as a Creature
In C++ you have to realize the different between value and reference semantics, where-as in interpretet languages you tend to just deal with reference semantics (except for some odd cases with plain old data objects which have value semantics but besides the point).
In C++ all objects are values, e.g an object can never be null, this has the implication that declaration specifies the storage requirement.
Consider the following
struct creature {
};
struct dog : public creature {
float cuteness;
};
The storage requirement for a dog is different than that of a creature, even if you allow the conversion this would result in slicing.
For example, will fido bark or be silent?
#include
class creature {
public:
virtual void speak() {
std::cout << "..." << std::endl;
}
};
class dog : public creature {
public:
virtual void speak() {
std::cout << "woof!" << std::endl;
}
};
int main(int argc, const char *argv[]) {
creature fido;
fido = dog();
fido.speak();
return 0;
}
However if you were to simply have a pointer or reference to the object it is a different matter.
By pointer.
creature* fido = new dog();
fido->speak();
delete fido;
By reference.
dog fido;
creature& c = fido;
c.speak();
Beyond the scope of this question, but optionally a smart pointer.
std::unique_ptr<creature> fido(new dog);
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.
Suppose I have a class Dog that inherits from a class Animal. What is the difference between these two lines of code?
Animal *a = new Dog();
Dog *d = new Dog();
In one, the pointer is for the base class, and in the other, the pointer is for the derived class. But when would this distinction become important? For polymorphism, either one would work exactly the same, right?
For all purposes of type-checking, the compiler treats a as if it could point to any Animal, even though you know it points to a Dog:
You can't pass a to a function expecting a Dog*.
You can't do a->fetchStick(), where fetchStick is a member function of Dog but not Animal.
Dog *d2 = dynamic_cast<Dog*>(d) is probably just a pointer copy on your compiler. Dog *d3 = dynamic_cast<Dog*>(a) probably isn't (I'm speculating here, I'm not going to bother checking on any compiler. The point is: the compiler likely makes different assumptions about a and d when transforming code).
etc.
You can call virtual functions (that is, the defined polymorphic interface) of Animal equally through either of them, with the same effect. Assuming Dog hasn't hidden them, anyway (good point, JaredPar).
For non-virtual functions which are defined in Animal, and also defined (overloaded) in Dog, calling that function via a is different from calling it via d.
The answer to this question is a giant: It depends
There are numerous ways in which the type of the pointer could become important. C++ is a very complex language and one of the ways it shows up is with inheritance.
Lets take a short example to demonstrate one of the many ways in which this could matter.
class Animal {
public:
virtual void MakeSound(const char* pNoise) { ... }
virtual void MakeSound() { ... }
};
class Dog : public Animal {
public:
virtual void MakeSound() {... }
};
int main() {
Animal* a = new Dog();
Dog* d = new Dog();
a->MakeSound("bark");
d->MakeSound("bark"); // Does not compile
return 0;
}
The reason why is a quirk of the way C++ does name lookup. In Short: When looking for a method to call C++ will walk the type hierarchy looking for the first type which has a method of the matching name. It will then look for a correct overload from the methods with that name declared on that type. Since Dog only declares a MakeSound method with no parameters, no overload matches and it fails to compile.
The first line allow you to call only members of the Animal class on a :
Animal *a = new Dog();
a->eat(); // assuming all Animal can eat(), here we will call Dog::eat() implementation.
a->bark(); // COMPILATION ERROR : bark() is not a member of Animal! Even if it's available in Dog, here we manipulate an Animal.
Although (as pointed by others), in this cas as a is still an Animal, you can't provide a as a parameter of a function asking for a more specific child class that is Dog :
void toy( Dog* dog );
toy( a ); // COMPILATION ERROR : we want a Dog!
The second line allow you to use specific functions of the child class :
Dog *a = new Dog();
a->bark(); // works, but only because we're manipulating a Dog
So use the base class as the "generic" interface of your class hierarchy (allowing you to make all your Animals to eat() whithout bothering about how).
The distinction is important when you call a virtual function using the pointer. Let's say Animal and Dog both have functions called do_stuff().
If Animal::do_stuff() is declared virtual, calling do_stuff() on an Animal pointer will call Dog::do_stuff().
If Animal::do_stuff() is not declared virtual, calling do_stuff() on an Animal pointer will call Animal::do_stuff().
Here's a full working program to demonstrate:
#include <iostream>
class Animal {
public:
void do_stuff() { std::cout << "Animal::do_stuff\n"; }
virtual void virt_stuff() { std::cout << "Animal::virt_stuff\n"; }
};
class Dog : public Animal {
public:
void do_stuff() { std::cout << "Dog::do_stuff\n"; }
void virt_stuff() { std::cout << "Dog::virt_stuff\n"; }
};
int main(int argc, char *argv[])
{
Animal *a = new Dog();
Dog *b = new Dog();
a->do_stuff();
b->do_stuff();
a->virt_stuff();
b->virt_stuff();
}
Output:
Animal::do_stuff
Dog::do_stuff
Dog::virt_stuff
Dog::virt_stuff
This is just one example. The other answers list other important differences.
No, they aren't the same.
The Dog pointer is not as polymorphic as Animal. All it can point to at runtime is a Dog or a subclass of Dog. If there are no subclasses of Dog, then the Dog runtime type and compile time types are the same.
The Animal pointer can refer to any subclass of Animal: Dog, Cat, Wildebeast, etc.
The difference is important when you try to call Dog's methods that are not Animal's method. In the first case (pointer to Animal) you have to cast the pointer to Dog first. Another difference is if you happen to overload non-virtual method. Then either Animal::non_virtual_method() (pointer to Animal) or Dog::non_virtual_method(pointer to Dog) will be called.
You must always remember there are 2 parts in every class, the data and the interface.
Your code truly created 2 Dog objects on the heap. Which means the data is of Dog.
This object is of size the sum of all data members Dog + Animal + the vtable pointer.
The ponters a and d (lvalues) differ as from a interface point of view. Which determines how you can treat them code wise. So even though Animal* a is really a Dog, you could not access a->Bark() even if Dog::Bark() existed. d->Bark() would have worked fine.
Adding the vtable back into the picture, assuming the interface of Animal had Animal::Move a generic Move() and that Dog really overwriten with a Dog::Move() { like a dog }.
Even if you had Animal a* and performed a->Move() thanks to the vtable you would actually Move() { like a dog }. This happens because Animal::Move() was a (virtual) function pointer re-pointed to Dog's::Move() while constructing Dog().
It makes no real difference at run time, as the two instances are the same. The only difference is at compile time, where you could call for example d->bark() but not a->bark(), even if a actually contains a dog. The compiler considers the variable to be an animal and only that.