C++ - Call Child Method Overwrites in List of Parents [duplicate] - c++

This question already has answers here:
What is object slicing?
(18 answers)
Closed 5 years ago.
Here's a sample program for what I'm talking about:
#include <iostream>
#include <list>
using namespace std;
class Thing {
public:
virtual void jump() { cout << "Called from Thing class" << endl; }
};
class Car: public Thing {
public:
virtual void jump() { cout << "Vroom vroom; imma car biotch" << endl; }
};
int main(int argc, char* argv[]) {
Car myCar;
list<Thing> myList;
myList.push_back(myCar);
std::list<Thing>::iterator iterator;
for (iterator = myList.begin(); iterator != myList.end(); ++iterator) {
iterator->jump();
}
return 0;
}
Output:
Called from Thing class
What I want to do is make a list of "Things". I want to be able to add instances of the child class from the Thing class; then I want to be able to call their overwritten function from an iterator.
The only issue is, even while using the "virtual" keyword, the iterator uses the Thing::jump function as opposed to the Car::jump function.
What can I do to make it not only work with Car, but all potential child classes from Thing, Car, etc. that overwrite the "jump" function?

In C++ values are what they say they are. You have a list of Thing not a list of Thing or derived types.
When you insert something into the list, a copy of it is created. In the case of inserting a derived type instance, this copies the Thing portion of the object, something known as object slicing (the Thing portion is sliced off).
There are a number of ways to store polymorphic data, but an instance of the base type is not one of them.
You could store std::unique_ptr<Base> in your list, for example. If you do so, ensure your base type has a virtual destructor to avoid undefined behaviour when theynare deleted by the default deleter.
#include <iostream>
#include <list>
#include <memory>
class Thing {
public:
virtual void jump() { std::cout << "Called from Thing class\n"; }
~Thing(){}
};
class Car: public Thing {
public:
virtual void jump() { std::cout << "Vroom vroom; I am a car\n"; }
};
then in main:
std::list<std::unique_ptr<Thing>> myList;
myList.push_back(std::make_unique<Car>());
for(auto&& ptr:myList){
ptr->jump();
}

Related

Do I need to initiate parent class or just child class

I am new in programing and I am analyzing code with parent class fruit and child classes apple and pear. In this example there is pointer to parent class. After I extended this code I find out that using object I can access parent public members and all child members. Question is why do I need those pointers?
// are this pointer needed since I can use j.setWeight(11)
#include <iostream>
using namespace std;
class fruit {
private:
int weight;
public:
void setWeight(int x)
{
weight = x;
}
int getWeight()
{
return weight;
}
};
class apple : public fruit {
public:
void eat()
{
cout << "Now I am eating apple"
<< "=" << getWeight() << endl;
}
};
class pear : public fruit {
public:
void eat()
{
cout << "Now I am eating pear"
<< " = " << getWeight() << endl;
}
};
int main()
{
apple j;
pear k;
fruit* fruit1 = &j;
fruit* fruit2 = &k;
k.setWeight(5);
k.eat();
fruit1->setWeight(11);
apple apple;
apple.postaviTezinu(16);
apple.jelo();
return 0;
}
are this pointers needed since I can use j.setWeight(11) and results is same as
fruit1 -> setWeight(11) ... what s difference, thx
I suspect that the code you are looking at was written to demonstrate how pointers to base classes can be used with objects of derived classes. No, pointers are not necessary for the functionality of this learning exercise. In fact, that is probably the reason this functionality was chosen. Since you see how to accomplish the same thing without pointers, it should be easier for you to relate pointers to what you already know.
The key learning points I see in this exercise are
The same pointer type (fruit *) can point to objects of different types (apple or pear).
When using the pointer to the base class, you can access base class members.
When using the pointer to the base class, you cannot access derived class members. (Implied by omission; compare what is done with k to what is done with fruit1.)
You will need to move on to the more advanced lessons to learn when pointers are more useful than accessing objects directly (probably after eat() is turned into a virtual function). For now, just learn how the same task can be accomplished by different means.
(Sure, you could get that information here, but that code looks like it's part of a series. Continuing with that series might be the better way to learn.)
Since you're new to programming, learning polymorphism may be a bit advanced for you at this stage. To answer your question directly: No, you don't need pointers in your example code, and they are in no way helpful.
However, pointers to objects are often useful for:
Reducing unnecessary copying of objects
In the case of polymorphism (as in your example) pointers help in sections of your programme where you don't know which object type you're dealing with, or don't want to have to deal with them in different ways
Example:
#include <iostream>
#include <vector>
class A
{
public:
virtual void foo ()
{
std::cout << " I am A\n";
}
};
class B : public A
{
public:
virtual void foo ()
{
std::cout << " I am B\n";
}
};
void bar ( const std::vector <A*> & obj )
{
// Here it outputs the foo () function that is
// appropriate for the class
for ( unsigned int i = 0; i < obj . size (); ++i )
obj [i] -> foo ();
}
int main ()
{
A a1, a2, a3;
B b1, b2, b3;
// the below input style requires C++11,
// otherwise input them one-by-one
std::vector <A*> array {&a1, &b1, &a2, &a3, &b2, &b3};
bar ( array );
return 0;
}
The above array can store any A objects, including the inherited objects (it can't do this without pointers); and the bar function can still perform operations on the elements in the array without needing to know which object type they belong to within the inheritance tree (due to the virtual function). This is crucial for taking advantage of polymorphism, and saving on repetition of functions and code in general.

How using object pointer with dynamic array

Hello I'm studying c++ language and I'm really wondering that if use object Pointer with dynamic array. Weapon class is derived by CItem class. At this time I'm typing like this.
CItem* pItem = new cWeapon[m_size];
and I doing initialize each object like this
pItem[0].initialize();
pItem[1].initialize();
pItem[2].initialize();
pItem[3].initialize();
....
pItem[n].initialize();
However this time make problem. Size is different pItem and cWeapon. Because Pointer Operation cause error.
and I wondering that how solve this problem?
sorry about my fool English skill.
Example code:
#include <iostream>
#include <memory>
#include <vector>
class BaseItem // abstract class
{
public:
virtual void initialize() = 0; // pure virtual function (no implementation)
};
class Sword : public BaseItem
{
public:
void initialize() override
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
class Shield : public BaseItem
{
public:
void initialize() override
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main()
{
std::vector<std::unique_ptr<BaseItem>> items;
items.emplace_back(new Sword);
items.emplace_back(new Sword);
items.emplace_back(new Shield);
items.emplace_back(new Sword);
items.emplace_back(new Shield);
for(auto& element : items)
{
element->initialize();
}
return 0;
}
You can run it here: wandbox.org
Output:
virtual void Sword::initialize()
virtual void Sword::initialize()
virtual void Shield::initialize()
virtual void Sword::initialize()
virtual void Shield::initialize()
In this implementation I used std::vector for dynamic arrays. Vector is containing types of smart pointer to BaseItem. In this case smart pointer is std::unique_ptr it helps a lot with resource management and it is easy to use. Without it you need manually delete all elements from vector. I really recomend using it.
Our BaseItem now can provide "interface" that we want to implement in any other class. If you don't want to force class to implement such method just don't make it pure virtual (remove = 0 and add {} body of function)
More information about:
C++ Abstract Class
__PRETTY_FUNCTION__
C++ virtual functions
C++ inheritance
This is kind of "old" approach. You can read also about composition and entity system (ES).

How should I store templated functions in any container?

I have a templated Prob class that acts as a way to organize various programming problems from different problem sets. The template is the problem number. How would I go about storing different Prob objects in a vector or map?
Here is the class declaration:
template<int ProbNum>
class Prob
{
std::string
text(std::ostream& out)
{
out << "Prob" << ((ProbNum < 10) ? "0" : "") << ProbNum << ": ";
}
void solve(std::ostream& out);
};
So in other words if I want to declare an object for problem 1 of some problem set I would do
Prob<1> p1;
and then store that in a map or vector for later use so the user can call on it during runtime (since you cannot pass a runtime argument into a template).
Edit: I want to use this class as an abstract class for other Prob classes.
Edit2: Added more code for clarification.
Edit3:
Top half is Prob1.hpp
Bottom half is a driver file on how I want to use it.
#include <iostream>
#include "Prob.hpp"
template<>
void
Prob<1>::solve(std::ostream& out)
{
out << "solution to prob1";
}
/***************************************************/
#include <iostream>
#include <cstdlib>
#include "Prob.hpp"
// Finished Problems
#include "Prob1.hpp"
int
main(int argc, char* argv[])
{
Prob<1> p;
p.solve(std::cout);
}
Each instance of a template class constitutes a different type. Hence, containers like std::vector cannot hold Prob<ProbNum> for different values of ProbNum.
If you know at compile time the number of Prob<ProbNum> instances you want, and the corresponding values of the template parameter int ProbNum you could store everything into a tuple. For example:
auto mycollection = std::make_tuple(Prob<1>(), Prob<2>());
A more general solution could be to define an abstract base class for Prob. Then you can manage to store a vector of Prob<ProbNum> objects, with inhomogeneous values of int ProbNum, if you define a vector of pointers to the base class. For this to work you must provide the interface in the base class, i.e., every member of Prob<ProbNum> that you want to access through the vector of the base class, must be virtual and already declared in the base class.
Consider the following example:
#include <iostream>
#include <memory>
#include <vector>
struct base {
virtual void print() const = 0;
virtual ~base() = default;
};
template <int i>
struct derived : public base
{
virtual void print() const { std::cout << i << std::endl; }
};
int main()
{
std::vector<std::unique_ptr<base>> vec;
vec.emplace_back(new derived<1>());
vec.emplace_back(new derived<3>());
vec.emplace_back(new derived<5>());
for (auto& el : vec)
el->print();
return 0;
}
The variable vec is essentially a vector of pointers to objects of type derived<i>, with inhomogeneous values of i. Because base::print() is virtual, it correctly resolves to the corresponding method of the derived<i> class.
Notice that I used a smart pointer to avoid memory leaking.
Also, it is important to declare virtual the destructor of base, see the discussion Why should I declare a virtual destructor for an abstract class in C++?.

Is an object valid in serialized form? c++/inheritance/serialization

I'm asking this because even tho it seems to work, I feel like it shouldn't. The goal is to have a collection of objects kept alive, and general access to them. This is what I have at the moment:
Take a base pointer access:
struct base { virtual void tick() = 0; }; //ptr access
With different types that inherit from it:
struct :public base
{
void tick() { cout << "im type 1" << endl; }
}type1;
struct :public base
{
void tick() { cout << "im type 2" << endl; }
}type2;
Then a container class that should be able to store any amount of these serialized:
class control
{
struct xtype //struct for organizing objects
{
vector<char>charbuf; //serialized object
}xtype_template;
vector<xtype>xtype_vec;
public:
template<typename T> base* tell_to(T &input) //take object, return (base*)
{
xtype_template.charbuf.resize(sizeof(input));
memcpy(xtype_template.charbuf.data(), (char*)&input, sizeof(input));
xtype_vec.push_back(xtype_template); //push back with template after filling
return (base*)xtype_vec[xtype_vec.size() - 1].charbuf.data(); //pointer to data
}
}xcontainer; //container object
Then call:
auto ptr = controller.tell_to(type1); //becomes base*
auto ptr2 = controller.tell_to(type2);
And you can access either static-sized serialized object, as well as its states, by doing:
ptr->tick(); //which will output "im type 1" to console
ptr2->tick() //"im type 2"
But is this legal? Do these serialized versions have an actual type? Is accessing a serialized object directly with a base pointer illegal or wrong?
Closest probable answer: as the return on is_trivially_copyable show false, objects might not be safe to manage after getting base inheritance.
Follow up: This approach seems to work, and fiddling with is_trivially_copyable, seems to suggest that making an object inherit methods from, makes it unsafe. Basic methods do not make it unsafe however, and that makes me wonder if the safety only applies to exporting between systems, saving to file, or transferring over the network. Maybe the check just assumes the virtual reference makes them unsafe?
Follow up 2: If the characters remain in the same spot in memory, does it matter how they are accessed? Id wager that the only real problem with this approach, is if the objects stored were to have elements that would change their size after being stored.
What you are doing is illegal. You can only memcpy an object as an array of chars when the object is TriviallyCopyable. And your object is not, since it has virtual functions.
Instead of doing this, you should simply store a (unique) pointer to newly allocated object, and avoid any casts to enforce hierarchy. Like this:
class xtype
{
std::unique_ptr<base> ptr;
public:
template<typename T> base* serial_acc(T &input) //take object, return (base*)
{
static_assert(std::is_base_of<base, T>::value, "Please use proper type");
ptr = std::make_unique<base>(input);
return ptr;
}
} xcontainer;
Working example given by user Andy Prowl
#include <vector>
#include <memory>
#include <iostream>
using namespace std;
struct base
{
virtual void tick() = 0;
};
struct type1 : base
{
virtual void tick() override { cout << "im type 1"<<endl; }
};
struct type2 : base
{
virtual void tick() override { cout << "im type 2" << endl; }
};
struct controller
{
vector<unique_ptr<base>> objects;
void cycle_tick(){ for (auto const& ptr : objects)ptr->tick();}
void add_object(unique_ptr<base> obj){ objects.emplace_back(move(obj));}
};
int main()
{
auto t1 = unique_ptr<type1>(new type1);
auto t2 = unique_ptr<type2>(new type2);
controller ctrl_object;
c.add_object(move(t1));
c.add_object(move(t2));
ctrl_object.cycle();
}

How can I have several inherited classes together in the same array?

I have a few classes, ObjDef, PeopDef, NpcDef, and PlyDef, such that PlyDef and NpcDef each seperately inherit PeopDef, and PeopDef inherits ObjDef. Each class has functionality that builds on the class before it, so it's important that PeopDef::Tick is called before ObjDef::Tick. I have every object stored in a vector<ObjDef> object, but when the main tick loop goes through them, I want them to call the original classes' Tick, rather than ObjDef::Tick, which is what the vector<ObjDef> currently makes it do. Is there any way to do this, or do I have to have a separate vector for each class?
You can store an ObjDef pointer (ObjDef* or a smart pointer) in the vector and make the Tick method virtual.
Here's an example:
#include <iostream>
#include <vector>
#include <memory>
class ObjDef
{
public:
virtual void Tick()
{
std::cout << "ObjDef::Tick\n";
}
};
class PeopDef : public ObjDef
{
public:
virtual void Tick()
{
std::cout << "PeopDef::Tick\n";
}
};
int main()
{
std::vector<std::shared_ptr<ObjDef>> objects;
std::shared_ptr<ObjDef> obj(new ObjDef());
std::shared_ptr<ObjDef> peop(new PeopDef());
objects.push_back(obj);
objects.push_back(peop);
for (auto object : objects)
{
object->Tick();
}
return 0;
}