I'll phrase this in the form of an example to make it more clear.
Say I have a vector of animals and I want to go through the array and see if the elements are either dogs or cats?
class Dog: public Animal{/*...*/};
class Cat: public Animal{/*...*/};
int main()
{
vector<Animal*> stuff;
//cramming the dogs and cats in...
for(/*all elements in stuff*/)
//Something to the effect of: if(stuff[i].getClass()==Dog) {/*do something*/}
}
I hope that's sort of clear. I know about typeid, but I don't really have any Dog object to compare it to and I would like to avoid creating a Dog object if I can.
Is there a way to do this? Thanks in advance.
As others has noted, you should neither use the typeid, nor the dynamic_cast operator to get the dynamic type of what your pointer points to. virtual functions were created to avoid this kind of nastiness.
Anyway here is what you do if you really want to do it (note that dereferencing an iterator will give you Animal* . So if you do **it you will get an Animal&):
for(std::vector<Animal*>::iterator it = v.begin(); it != v.end(); ++it) {
if(typeid(**it) == typeid(Dog)) {
// it's a dog
} else if(typeid(**it) == typeid(Cat)) {
// it's a cat
}
}
Note you can apply the typeid operator to types itself too, as shown above. You don't need to create an object for this. Also note the typeid way doesn't work if you pass it a pointer like typeid(*it) . Using it like that will give you just typeid(Animal*) which isn't useful.
Similar, dynamic_cast can be used:
for(std::vector<Animal*>::iterator it = v.begin(); it != v.end(); ++it) {
if(Dog * dog = dynamic_cast<Dog*>(*it)) {
// it's a dog (or inherited from it). use the pointer
} else if(Cat * cat = dynamic_cast<Cat*>(*it)) {
// it's a cat (or inherited from it). use the pointer.
}
}
Note that in both cases, your Animal type should be polymorph. That means it must have or inherited at least one virtual function.
You can use dynamic_cast, as long as the vector contains Animal pointers.
vector <Animal *> stuff;
for(int i=0;i<stuff.size();i++) {
Dog *pDog = dynamic_cast <Dog *> (stuff[i]);
if(pDog) {
// do whatever with the dog
}
Cat *pCat = dynamic_cast <Cat *> (stuff[i]);
if(pCat) {
// and so on
}
}
but you should be aware that this is generally not the best practice. You should try to work with polymorphism, not against it. In other words, try to write a virtual Animal function that Dog and Cat override, and let the compiler automagically call the right one.
(Also, dynamic_cast is relatively slow, so too many of them will hinder performance; whereas a virtual function call is general just a single instruction.)
Are you sure you want to do that? What you're going to do is the exact contrary of polymorphism, and polymorphism is the best thing in object-oriented programming.
Loosely speaking: Don't do something if you animal is a Dog; let the Animal hierarchy know what to do when one of its objects is a Dog! :)
If you really need your application-level to identify Dogs vs non-Dogs, you should avoid using RTTI (dynamic_cast and typeid), and make that knowledge explicit in your class hierarchy.
for (size_t i = 0; i != v.size(); ++i) {
if (v[i]->isDog()) { v->cleanupPoop(); }
}
There are some minor performance benefits, but the primary benefit is exposing the necessary behavior in your class interface to maintenance programmers. RTTI (being as limited as it is) should not be required in order for a class hierarchy to function.
Now, along with what other people have said, it's likely that the isDog() function could be refactored into something that doesn't require knowledge of the entire hierarchy up-front (such as needsPoopCleanup()). Like everyone else said, you're losing the benefits of polymorphism if your application logic conditionally executes based on object type anyhow.
You can use the typeid operator to do this, e.g.
if (typeid(stuff[i].getClass())==typeid(Dog))
This can't catch if it's a derived class of Dog, though. You can use a dynamic_cast for that. However, any use of typeid or dynamic_cast is often indicative of a design flaw. Usually, you don't need to know what your derived types are, and there's probably a better way that involves polymorphism. It's hard to give the right advice without a real example, though.
using virtual functions:
As indicated by others responses, using virtual functions will often actually be sufficient enough, and is the "C++" way of thinking. Here is an example of using virtual functions:
#include<iostream>
#include<vector>
using namespace std;
/////////////
class Animal {
public:
virtual void move() { cout << "animal just moved" << endl; }
};
class Dog : public Animal {
public:
void move() { cout << "dog just moved" << endl; }
};
class Cat : public Animal {
public:
void move() { cout << "cat just moved" << endl; }
};
void doSomethingWithAnimal(Animal *a) {
a->move();
}
/////////////
int main() {
vector<Animal*> vec;
vector<Animal*>::iterator it;
Animal *a = new Animal;
Dog *d = new Dog;
Cat *c = new Cat;
vec.push_back(a);
vec.push_back(d);
vec.push_back(c);
it = vec.begin();
while( it != vec.end() ) {
doSomethingWithAnimal(*it);
it++;
}
return 0;
}
If this will not be sufficient, then others have already posted answers which actually use conditional logic instead of polymerized logic.
The accepted answer is correct, but you should know that there is another option as well that hasn't been mentioned. You could have a virtual function in the Animal class called "type()" which could return an int or a string (or any type that is comparable).
So for example:
class Animal {
/*...*/
public:
virtual std::string type() const { return "animal"; }
};
class Dog: public Animal{
/*...*/
public:
virtual std::string type() const { return "dog"; }
};
class Cat: public Animal{
/*...*/
public:
virtual std::string type() const { return "cat"; }
};
This way you could just do:
if(array[i]->type() == "dog") { }
The type function could return anything (an int unique to each derived type would work too, but strings illustrate it better).
Simply another option.
Related
I have a class AnimalInterface in Animal namespace:
namespace Animal
{
class AnimalInterface
{
public:
AnimalInterface() = default;
virtual ~AnimalInterface() = default;
virtual std::string makeSound() = 0;
};
}
Suppose I have 2 classes implementing from this interface
class Dog : public AnimalInterface
{
public:
Dog() = default;
~Dog() = default;
std::string makeSound()
{
return "Bark";
}
};
class Cat : public AnimalInterface
{
public:
Cat() = default;
~Cat() = default;
std::string makeSound()
{
return "Meow";
}
};
Now I have a class from where I call these functions. I would like to be able to get the class names of the animals from the objects using run time type information.
void AnimalSounds
{
list<unique_ptr<AnimalInterface>> animals;
animals.push_back(make_unique<Dog>());
animals.push_back(make_unique<Cat>());
for (const auto& animal : animals)
{
cout << typeid(animal).name() << " makes sound: " << animal->makeSound() << endl;
}
}
I expect the output to be
Dog makes sound: Bark
Cat makes sound: Meow
Instead, I get the following
class std::unique_ptr<class Animal::AnimalInterface,struct std::default_delete<class Animal::AnimalInterface> > makes sound: Bark
class std::unique_ptr<class Animal::AnimalInterface,struct std::default_delete<class Animal::AnimalInterface> > makes sound: Meow
How do I fix this? Thanks!
You need to dereference the pointer. That way you get the RTTI information from the object that it points to, not the pointer itself:
const auto& animal_ref = *animal;
cout << typeid(animal_ref).name() << " makes sound: " << animal->makeSound() << endl;
3Dog makes sound: Bark
3Cat makes sound: Meow
Note that you will still have to deal with implementation-defined names as described in the comments. You can use your library's demangle function for that:
int status;
const auto& animal_ref = *animal;
const auto name = abi::__cxa_demangle(typeid(animal_ref).name(), 0, 0, &status);
cout << name << " makes sound: " << animal->makeSound() << endl;
Dog makes sound: Bark
Cat makes sound: Meow
Unless this question was asked for a better understanding of RTTI or for debugging purposes, I would still strongly advise you to reconsider your approach. This is nothing that your code should rely on.
(And yes, technically even demangling might not be enough, and the name might change between invocations. In the implementations that I have worked with, this never happened. At the point where we are talking about cats making meow, this is more a technicality than an actual issue.)
I think the unexpected problem you have is that your animals list contains unique_ptr to Animals. Therefore, when you iterate over that list, each animal in the loop is a unique_ptr<Animal>, which is a template with default arguments. To at least fix that problem, dereference the pointer before using typeid:
for (const auto& animal : animals)
{
cout << typeid(*animal).name() << " makes sound: " << animal->makeSound() << endl;
}
However, what you get here is still implementation defined. Read up on RTTI for more information.
1.) animal is a reference to some element from animals. What does animals contain? It contains unique_ptr<AnimalInterface>, so the compiler prints exactly the right thing, just a bit verbose.
2.) typeif(...).name() is not really refelction. In particular it doesn't give you any garantues about the result whatsoever. See also the reference:
No guarantees are given; in particular, the returned string can be identical for several types and change between invocations of the same program.
3.) I can only think of one robust and standard compliant way to achieve what you want to: another virtual function that returns the animal kind. Or some compiler specific extension, but standard C++ doesn't offer any real reflection at the moment.
I'm trying to achieve something illustrated with this piece of code, but I can't get it to work. I can't return an Animal, and I really don't think returning an Animal* would be a good solution, because I'd have to new and delete manually.
EDIT: I updated the question with a more specific code snippet, demonstrating why returning Animal* isn't a really good idea.
As you can see from the snippet, I basically want to use an Animal as
an interface for a bunch of data, and that data may be part of an array
or it may be a more conventional object.
EDIT 2: Working example: http://ideone.com/4qp3qT
Remaining problems:
duplicate code (FeedAnimals())
performance?
having to delete manually (for the cats)
#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <stdlib.h>
using namespace std;
class Animal {
virtual void eat() = 0;
};
// Dog is more high-level
class Dog: public Animal {
char attr1;
char attr2;
Dog(_attr1, _attr2):
attr1(_attr1),
attr2(_attr2)
{}
Dog():
attr1('d'),
attr2('g')
{}
void eat() {
cout << "Dog ate food (" << attr1 << attr2 << ").\n";
}
void barf() {
cout << "Whaf";
}
};
// Cat is more low-level
class Cat: public Animal {
// A cat can basically only exist in a cage
// and it's attributes are defined by it's location
// in the Cage's underlying array. A Cat should also
// have to 2 attributes (both char), so this would
// be kind of true:
// sizeof(Cat) == 2
char* ptr;
// I will only use a Cat in a context of arrays, so
// no need to care about memory management here.
Cat(char* _ptr):
ptr(_ptr)
{}
void eat() {
cout << "Cat ate food (" << *ptr << *(ptr+1) << ").\n";
}
void meow() {
cout << "Meow.";
}
};
class Cage {
virtual Animal GetRandomAnimal() = 0;
};
// DogCage uses a nice (more high level) vector
class DogCage {
vector<Dog> dogs;
DogCage():
dogs(5)
{}
Animal GetRandomAnimal() {
// ?
}
}
// CatCage uses a more low level pointer together with
// malloc etc.
class CatCage {
char* cats;
CatCage():
cats((char*) malloc(4*2)) // room for 4 cats
{}
~CatCage() {
free(cats);
}
Animal GetRandomAnimal() {
// ...
// This is why it's difficult to return a pointer
// to an Animal. I basically want to use a Cat as
// a simple interface to a part of an array.
// If I use pointers etc, that seems like it would
// hit performance.
return Cat(cats+(random*2))
}
}
void FeedAnimals(Animal& a) {
a.eat();
}
int main() {
Cage cage; // ?
string s;
cout << "Cats or dogs?";
cin >> s;
if (s=="Cats") {
cage = CatCage(); // ?
} else {
cage = DogCage(); // ?
}
// fill cage with animals (either cats or dogs)
FeedAnimals(cage.GetRandomAnimal());
}
Your real problem is that you're arbitrarily trying to avoid using the tools (pointer, reference, or smart pointer) available for the job.
I'm guessing, this is because you are familiar with some other language that seems to permit this. The thing is, languages which do such things do it by blending concepts of object, reference, and pointer in ways that C++ does not.
It is not possible in C++ to return an abstract class by value. Period. Returning a class by value means it is necessary to instantiate it and an abstract class is one that cannot be instantiated.
If your function returns a raw reference or pointer, it is necessary that the objects exist when the caller uses them, and that the objects are released (cease to exist) when no longer needed. Either that means your function accepts responsibility for managing object lifetime (e.g. the object is an element of an array) or that the caller is (e.g. function dynamically creates object, caller releases it when done).
Returning a smart pointer means returning an object that manages lifetime of the contained object. The function creates the object, hands it to a smart pointer, and the smart pointer is returned to the caller. When the smart pointer no longer exists (e.g. caller returns so it passes out of scope), the object is released.
Pointers don't have to point to dynamic objects, and only need delete if they do (in which case consider a smart pointer).
In the case of the animals, you can just return a reference or pointer to one of the animals in the cage.
Animal & GetRandomAnimal() {
return cats[GetRandomIndex()];
}
For the cage itself, dynamic allocation is the easiest way to make it polymorphic; but you should use a smart pointer to avoid faffing around with delete and debugging memory leaks.
std::unique_ptr<Cage> cage;
if (s=="Cats") {
cage.reset(new CatCage); // C++14: cage = std::make_unique<CatCage>();
} else {
cage.reset(new DogCage); // C++14: cage = std::make_unique<DogCage>();
}
If you're stuck in the past, replace unique_ptr with auto_ptr, boost::scoped_ptr, or a hand-rolled equivalent.
You can't return an Animal because you can't create an Animal (it's an abstract type). You need something that any Animal (Cat, Dog, etc.) can hide behind: a pointer or a reference. If you create all your animals beforehand, you could return a (preferably const) reference:
Cat cat;
Dog dog;
Animal const& GetRandomAnimal()
{
if (rand() == 42) {
return cat;
}
else {
return dog;
}
}
However, if you want to return an animal object (instance) which didn't exist before, your only option is to create on the heap and return a pointer. Returning a pointer has the problem that it's unclear who is responsible for deleting the object. With C++11, your best bet is to return a smart pointer:
std::unique_ptr<Animal> GetRandomAnimal()
{
if (rand() == 42) {
return std::make_unique<Cat>(/*args to the cat constructor*/);
}
else {
return std::make_unique<Dog>(/*args to the dog constructor*/);
}
}
or use std::shared_ptr and std::make_shared.
(alas, std::make_unique is C++14)
I'm pretty new to C++ and am having trouble making a pointer point from one class to another. This is what I have, it compiles without error, but doesn't work the way I want it to.
JungleMap *Map;
class JungleMap
{
public:
void goNorth()
{
cout << "You are going north towards the river.\n";
delete[] Map;
RiverMap *Map;
}
}
class RiverMap
{
public:
void goNorth()
{
cout << "You are going north away from the river.\n";
delete[] Map;
JungleMap *Map;
}
}
int main()
{
Map->goNorth();
Map->goNorth();
}
This is what the output is:
You are going north towards the river.
You are going north towards the river.
And this is what I would like the output to be:
You are going north towards the river.
You are going north away from the river.
How do I achieve this? It's really bugging me, especially since it compiles without problems.
Just creating a JungleMap* doesn't create a JungleMap. You formed a pointer, but didn't point it anywhere!
This is particularly dangerous since you then dereference it, and later attempt to delete through it. Yes, this compiles, because a compiler cannot diagnose this in the general case (and is never required to try), but you'll get everything at runtime from silent nothingness, to a crash, to a nuclear explosion.
You are also trying to invoke different functions in two different classes, through changing the type of a pointer (without any inheritance, at that), which is simply not possible and will prevent your code from compiling, even though you've tried to get around it by redeclaring variables locally. I could list a ream of misunderstandings but suffice it to say it's time to read a good introductory C++ book.
I would suggest a combination of inheritance and dynamic allocation, if I knew what you were trying to achieve. A common mistake on SO is to provide nonsense code, then expect us to know what your goal is from that nonsense code; unfortunately we have about as much idea what you really meant to do as the C++ compiler does!
You could make this work (to at least a minimal degree) by creating a base class from which both JungleMap and RiverMap derive. You'd then have a pointer to the base class, which you'd point at an instance of one of the derived classes. You'll also need to rearrange the code somewhat to get it to compile.
class Map {
public:
virtual void goNorth() { cout<<"Sorry, you can't go that way"; }
virtual void goSouth() { cout<<"Sorry, you can't go that way"; }
};
Map *map;
class RiverMap;
class JungleMap : public Map {
public:
void goNorth();
};
class RiverMap : public Map {
public:
void goSouth();
};
void JungleMap::goNorth() {
cout<<"You are going north towards the river.\n";
delete map;
map=new RiverMap;
}
void RiverMap::goSouth() {
cout<<"You are going south towards the jungle.\n";
delete map;
map=new JungleMap;
}
Note: here I'm just trying to say as close to your original design as possible and still have some code that might at least sort of work. I'm certainly not holding it up as an exemplary design, or even close to it (because, frankly, it's not).
What you should do is to sit down and think about the problem you are trying to solve, and make a proper design. In your case you have two "locations", and the "player" should be able to move between these locations. Starting from that we have identified two possible classes (Location and Player) and one behavior (the player can move from location to location).
With the above information, you could do something like this:
class Location
{
public:
void setNorth(Location* loc)
{
north_ = loc;
}
Location* getNorth() const
{
return north_;
}
void setSouth(Location* loc)
{
south_ = loc;
}
Location* getSouth() const
{
return south_;
}
void setDescription(const std::string& descr)
{
description_ = descr;
}
const std::string& getDescription() const
{
return description_;
}
protected:
Location() {} // Made protected to prevent direct creation of Location instances
private:
Location* north_;
Location* south_;
std::string description_;
};
class Jungle : public Location
{
public:
Jungle() : Location()
{
setDescription("You are in a jungle.");
}
};
class River : public Location
{
public:
River() : Location()
{
setDescription("You are close to a river.");
}
};
// The actual "map"
std::vector<Location*> map
void createMap()
{
map.push_back(new Jungle);
map.push_back(new River);
map[0]->setNorth(map[1]);
map[1]->setSouth(map[0]);
}
class Player
{
public:
Player(Location* initialLocation)
: currentLocation_(initialLocation)
{
std::cout << currentLocation_->getDescription() << '\n';
}
...
// Other methods and members needed for a "player"
void goNorth()
{
if (currentLocation_ && currentLocation_->getNorth())
{
currentLocation_ = currentLocation_->getNorth();
std::cout << currentLocation_->getDescription() << '\n';
}
}
void goSouth()
{
if (currentLocation_ && currentLocation_->getSouth())
{
currentLocation_ = currentLocation_->getSouth();
std::cout << currentLocation_->getDescription() << '\n';
}
}
private:
Location* currentLocation_; // The players current location
};
int main()
{
createMap(); // Create the "map"
Player player(map[0]); // Create a player and place "him" in the jungle
// Move the player around a little
player.goNorth();
player.goSouth();
}
In the code above, you have a single player object, which have a "current location". When you move the player around, you simply change the current location for that player. The current location of the player acts as the global Map variable you have.
Note: I'm not saying that this is a good design or code, just that it's simple.
However, if you're truly new to C++, you should probably start with some simpler problems, including tutorials on pointers and inheritance.
You appear to be confusing declaration with assignment.
The following line of code is called a declaration, it tells the compiler the properties and attributes of a thing.
JungleMap *Map;
After this line of code, the compiler knows that "Map" is a symbol (a name) referring to a pointer to a JungleMap.
The compiler doesn't have to do anything with a declaration, unless it would have a side effect, at which point it becomes a definition, which means that the declaration invokes a non-trivial constructor or provides an assignment:
struct Foo {};
struct Baz { Baz() { std::cout << "Baz is here\n"; } };
These are declarations - they don't create instances of objects, they describe the layout and functions for instances. At some point you have to create a concrete instance of them with a definition or a call to new.
struct Foo {};
struct Bar { Bar() { std::cout << "Bar is here\n"; } };
struct Baz {};
int main() {
int i; // no side effects, i is trivial.
char* p; // no side effects, p is a pointer (trivial) type
std::string* sp; // trivial, pointer
Foo f; // trivial
Bar b; // non-trivial, baz has a user-defined ctor that has side-effects.
Bar* bar; // trivial, unassigned pointer type.
Bar* bar2 = new Bar(); // side effects.
Bar bar(); // syntax error, "the most vexing parse"
}
In the above code, we never use "Baz" and we never declare an object of type Baz so the compiler essentially throws it away. Because so many of the variables are trivial and have no side effect, the result of compiling the above will be functionally equivalent to if we had written:
struct Foo {};
struct Bar { Bar() { std::cout << "Bar is here\n"; } };
int main() {
Bar* bar2 = new Bar(); // side effects.
Bar bar(); // syntax error, "the most vexing parse"
}
All of the rest does nothing.
C++ also allows you to re-use names as long as they are in different scopes, but this creates a new, hidden ("shadow") thing:
#include <iostream>
int main() {
int i = 1;
if (i == 1) {
float i = 3.141;
std::cout << "inner i = " << i << '\n';
}
std::cout << "outer i = " << i << '\n';
return 0;
}
The code you wrote will therefore compile, because it is declaring a new and private "Map" inside each of the go functions and then simply never using them.
Note that above I was able to declare i differently inside the inner scope than the outer.
C++ does not allow you to change the type of a variable - in the above code there are two variables called i. When we created the second i, it is a second variable called i the original variable didn't change.
In order to do what you are trying to do, you're going to need to learn about "polymorphism" and "inheritance", C++ concepts that will allow you to describe a "Room" or "Location" and then base JungleMap and RiverMap on that base definition such that you can take a pointer to the core concept, the Room, and write generic code that deals with rooms while moving the specifics of Jungle, River or BridgeMap into specialized functions. But I think that's beyond the scope of a reply here.
My case is the following: In my larger program I want to make an interface to grab frames from a imagesource. However, in the program I do not know in advance whether I want to grab frames from a camera or from a video file. But I would like to have one interface that handles video files and camera frames as identical. This in total is is taking much code to accomplish, thus I'll present a very short example.
this is the example of the interface:
class Input {
public :
virtual void
get_frame() = 0;
};
This is a derived class that should grab frames from a camera.
class CameraInput: public Input {
public :
void get_frame();
};
This is the class that should open a videofile and grab frames from the file.
class VideoInput: public Input {
public :
void get_frame();
};
Here are the definitions of the get_frame from the Input derived classes. As you can see they "produce" a different type of video frame.
void
CameraInput::get_frame(){
std::cout << "camera-frame" << std::endl;
};
void
VideoInput::get_frame() {
std::cout << "video-frame" << std::endl;
};
This it the code that instantiates an object of type CameraInput or VideoInput.
Edit shared pointer added
typedef enum { VIDEO, CAMERA } input_type ;
std::shared_ptr<Input> framegrabber;
/*Does this have to be a pointer?*/
/*In my program I don't know this in advance.*/
input_type my_input = CAMERA;
switch ( my_input ){
case CAMERA:
framegrabber = std::shared_ptr<Input>(new CameraInput);
break;
case VIDEO:
framegrabber = std::shared_ptr<Input>(new VideoInput);
break;
default:
/*error handling here*/
break;
};
framegrabber->get_frame();
On stackoverflow I read many times in c++ answers, that one should never use pointers unless one really, really needs to. This is where my question comes from, is it possible and better to rewite the code above without using a Input* or is this one of the case where it is mandatory to use pointers?
kind regards,
On stackoverflow I read many times in c++ answers, that one should never use pointers unless one really, really needs to.
When you read any advice, you should try to understand WHY this advice is given. If there's no good reason behind advice, there's no need to follow that advice.
Trying to eliminate all pointers from your program just because somebody told you "pointers are bad" is not a good idea.
Experienced programmers tell you to avoid raw pointers, because pointers mean manual memory management, which is error prone (forget to delete something == memory leak), plus you have to be aware of rule of three.
I also have impression that inexperienced programmers frequently give the same advice because they simply do not understand pointers completely (or are afraid of them?).
You CAN use references, but because you can't copy/reassign references that'll be less useful. Example:
#include <iostream>
class A{
public:
virtual int getVal() const = 0;
virtual ~A(){}
};
class B: public A{
public:
virtual int getVal() const { return 2; };
};
class C: public A{
public:
virtual int getVal() const { return 3; };
};
class D{
public:
const A& getInterface(bool which) const{
if (which)
return c;
return b;
}
protected:
B b;
C c;
};
int main(int argc, char** argv){
D d;
std::cout << d.getInterface(true).getVal() << std::endl;
std::cout << d.getInterface(false).getVal() << std::endl;
return 0;
}
As you can see, to return object by reference, you'll need to create it somewhere, and store it. If you want to "kill all pointers", then you'll need to create this object as a member variable of bigger class (or as a global variable).
With pointer, you could simply return shared_ptr<A>.
In your code, the better idea would be to use smart pointer class instead of raw pointers. That'll eliminate need for manual delete/memory management.
it possible and better to rewite the code above without using a Input*
Yes, it is possible, but there's no reason to do it, and this is (IMO) NOT better. My example illustrates how you could do it. Without pointers(of any kind - smart or raw) you'll also have to store BOTH CameraInput and VideoInput somewhere, while with pointers you can create them on demand.
You could use a smart pointer (e.g. std::unique_ptr or std::shared_ptr) instead of the raw pointers.
If you want polymorphism, you must use pointers or references. There are far more details than you really want here
Actually I'm new to C++. I tried something out (actually the map container) but it doesn't work the way I assumed it will... Before posting my code, I will explain it shortly.
I created 3 classes:
ClassA
ClassDerivedA
ClassAnotherDerivedA
The two last ones are derived from "ClassA".
Further I created a map:
map<string,ClassA> test_map;
I put some objects (from Type ClassDerivedA and ClassAnotherDerivedA) into the map. Keep in mind: the mapped value is from type "ClassA". This will only work because of Polymorphism. Finally I created an iterator which runs over my map and compares the user input with my keys in the map. If they match, it will call a specific method called "printOutput".
And there is the Problem:
Although i declared "printOutput" as "virtual" the only method called is the one from my base class, but why?
and here is the code:
#include <iostream>
#include <map>
using namespace std;
class ClassA
{
public:
virtual void printOutput() { cout << "ClassA" << endl; }
};
class ClassDerivedA : public ClassA
{
public:
void printOutput() { cout << "ClassDerivedA" << endl; }
};
class ClassAnotherDerivedA: public ClassA
{
public:
void printOutput() { cout << "ClassAnotherDerivedA" << endl; }
};
int main()
{
ClassDerivedA class_derived_a;
ClassAnotherDerivedA class_another_a;
map<string,ClassA> test_map;
test_map.insert(pair<string,ClassA>("deriveda", class_derived_a));
test_map.insert(pair<string,ClassA>("anothera", class_another_a));
string s;
while( cin >> s )
{
if( s != "quit" )
{
map<string,ClassA>::iterator it = test_map.find(s);
if(it != test_map.end())
it->second.printOutput();
}
else
break;
}
}
The problem is slicing. You are storing ClassA values in your map. When you store derived class instances into the map, the get sliced into ClassA objects. You'll need to store pointers in your map instead of values.
See this for more info on slicing: What is object slicing?
C++ is not Java. You cannot store a derived type in a variable of a base type. For example:
Base b = Derived();
will only store the Base part of Derived in the variable b. In order to get polymorphic behaviour, you would need to use pointers, and create the derived class dynamically:
Base * b = new Derived();
The same goes for C++ containers - you need:
map <string, Base *> m;
All of this should be covered in every introductory C++ text book - which one are you using?
You are experiencing "slicing". To get the virtual functions to work properly, you need to call them using a pointer or a reference. In other words, your map should contain pointers to ClassA:
map<string, ClassA *> test_map
Please remember to delete them when you are done, or use smart pointers.
Here's more on slicing: here, here, and here