I am storing an objects with common parent in stl container (actually stack), but calling a virtual function on object inside of it results in calling an implementation in this common parent. See demo code:
#include <iostream>
#include <stack>
using namespace std;
class Z
{
public:
virtual void echo()
{
cout << "this is Z\n";
}
int x;
};
class A: public Z
{
public:
virtual void echo()
{
cout << "this is A\n";
}
};
int main()
{
A a;
a.x = 0;
Z z;
z.x = 100;
stack<Z> st;
st.push(a);
st.top().echo(); // prints "This is Z"
cout << "x = " << st.top().x << endl; // prints 0
st.push(z);
st.top().echo(); // prints "This is Z"
cout << "x = " << st.top().x << endl; // prints 100
return 0;
}
In general, containers of objects and polymorphism don't mix : You are slicing your objects of type A into objects of type Z when you push them in the container (because the container is really expecting and storing objects of sizeof(Z))
Use std::stack<Z*>, or std::stack<std::unique_ptr<Z>> to manipulate pointers to your base class.
See also : What is the slicing problem in C++?
You have slicing:
You should use std::stack<Z*> or std::stack<std::unique_ptr<Z>>.
What you observe is slicing. Your stack stores Z objects, so even if you construct an A object, it will not be stored in the stack - an Z object will be constructed from A and stored.
You cannot store in container by value if you want polymorphism. Use stack<unique_ptr<Z>>.
Related
So as you can see down below, I try increment the x value of the bird by 1. But the value gets reset every time I call the getX() function.
#include <iostream>
#include <vector>
class Bird {
public:
Bird(double inputX, double inputY) : x(inputX), y(inputY) {
}
void tick() {
x++;
}
double getX() {
return x;
}
double getY() {
return y;
}
private:
double x, y;
};
class Test {
public:
void addToVector(double x, double y) {
Bird bird(x, y);
birds.push_back(bird);
}
std::vector<Bird> getVector() {
return birds;
}
private:
std::vector<Bird> birds;
};
int main(int argc, char* agrs[]) {
Test test;
for (int i = 0; i < 5; i++) {
test.addToVector(0, 0);
}
for (int i = 0; i < test.getVector().size(); i++) {
std::cout << "Index: " << i << " x: " << test.getVector()[i].getX() << " y: " << test.getVector()[i].getY() << std::endl;
}
while (true) {
for (int i = 0; i < test.getVector().size(); i++) {
test.getVector()[i].tick();
}
for (int i = 0; i < test.getVector().size(); i++) {
std::cout << "Index: " << i << " x: " << test.getVector()[i].getX() << " y: " << test.getVector()[i].getY() << std::endl;
}
}
}
So I know, that the problem is that I create the bird in the function and "copy" it to the vector. But the bird goes out of scope so I get a memory leak. I tried using unique pointers, but I couldn't declare the bird with a name because of that. I also don't know how to prevent that the destruction of the bird
So I know, that the problem is that I create the bird in the function and "copy" it to the vector
No. That's not a big problem. You could create the bird directly in the vector rather than first creating one then then copy it in the vector. Though, making the copy is not the reason for the output you get, its just a copy that could be avoided.
But the bird goes out of scope so I get a memory leak.
No. There is also no memory leak in your code.
I tried using unique pointers, ...
Hm, ok. Not sure what you did, or what was the problem with that code. Anyhow, the actual problem is...
Your getVector returns a copy of the member. Modifying that copy has no effect on the member. The easy fix to get expected output is to change the getter to return a reference:
std::vector<Bird>& getVector() {
return birds;
}
However, now the question arises why birds is private in the first place. Once you return a non-const referene to the outside of the class the caller can use this reference to do what they like, just as if the member was public.
Rather than designing your classes as data containers with getters and setters to set and get their members you should design the classes according to their behavior (unless the aim is to implement a plain data container of course). Here, rather than returning the whole vector to the caller you could let the caller specify which bird they want to tick and provide a mehtod to print contents of the vector. Something along the line of (not tested, and not changing Bird other than removing one member):
class Bird {
public:
Bird(double inputX) : x(inputX) {}
void tick() { x++; }
double getX() const { return x; } // should (/must) be const !
private:
double x;
};
class Birdies {
public:
void addToVector(double x) {
birds.push_back(x); // still creates a tempory that is copied, look at emplace_back
}
void makeTick(size_t index) {
birds[index].tick();
}
void print() const {
for (const auto& b : birds) std::cout << b.getX() << "\n";
}
private:
std::vector<Bird> birds;
};
No, you are misunderstanding the problem, it has nothing to do with the destruction of any bird object.
The problem is here
std::vector<Bird> getVector() {
return birds;
}
This function returns a copy of the vector in the Test object. So when you call tick you are modifying a copy of the vector not the original.
Change to this to return a reference to the vector, not a copy
std::vector<Bird>& getVector() {
return birds;
}
Say I have something like this:
int main()
{
Base *array[2];
array[0] = new Base("Hello", 2);
array[1] = new Derived("Bye", 3, 5);
DisplayEverything(array[0]);
DisplayEverything(array[1]);
cout << endl << "Deleting...." << endl << endl;
for (int i = 0; i < 2; i++) {
delete array[i];
}
}
and a non-member function that prints the Base and Derived objects:
void DisplayEverything(Base* a)
{
a->print();
}
In both Base and Derived classes, I have setup a virtual destructor and a virtual print function like: virtual void print();
void Base::print()
{
cout << a << " " << b << endl;
}
and:
void Derived::print()
{
cout << get_a() << " " << get_b() << " " << c << endl;
}
This would do what is expected, but is there any way I can pass an object instead of a pointer instead? I'd like the function to be something like this:
void DisplayEverything (Base a)
{
a.print();
}
How would I do something like this?
I am not sure why it's not possible because I have done it once, but I ran into object slicing problem, here is what I had:
Base *array;
array = new Base [2];
array[0].set_info("Hi", 1, 2);
DisplayEverything(array[0]);
with the DisplayEverything function now as this:
void DisplayEverything (Base a)
{
a.print();
}
Firstly, some guidelines:
Do not use raw pointers for memory management. Use smart pointers such as std::unique_ptr. In Modern C++ new and delete should almost never appear in your source code.
Do not use inheritance unless you have a clear extensible hierarchy of things sharing the same interface. std::variant might be more appropriate for your use case (and has value semantics).
Do not use C-style arrays, prefer std::array from the <array> header.
is there any way I can pass an object instead of a pointer instead?
If you want virtual dispatch at run-time through polymorphic inheritance, the answer is no. You need to pass either a pointer (std::unique_ptr if owning) or a reference.
If you want the dispatch to happen at compile-time, you can use a template:
template <typename T>
void DisplayEverything (T a)
{
a.print();
}
Alternatively, if you want run-time dispatch with value semantics for a closed set of types, use std::variant.
I need to register object in global list. I know I can't use make_shared_from_this in constructor - what do I use instead?
vector<shared_ptr<A> > alpha;
struct A : enable_shared_from_this<A>
{
int x;
A():x(9)
{
//alpha.push_back(shared_from_this());
//alpha.push_back(shared_ptr<A>(this));
}
};
1) first push back would result in crash:
ibc++abi.dylib: terminating with uncaught exception of type std::__1::bad_weak_ptr: bad_weak_ptr
2) second push back would result in segmentation fault
You cannot use shared_from_this from constructor and you actually don't need shared_from_this here. You can just write something like create function.
vector<shared_ptr<A> > alpha;
// in struct A
static shared_ptr<A> create()
{
shared_ptr<A> pointer = make_shared<A>();
alpha.push_back(pointer);
return pointer;
}
put constructor in private location and use any trick from How do I call ::std::make_shared on a class with only protected or private constructors?
Is the global vector just meant to list all the objects in memory or do you actually delete objects from the vector. In the later case ForEveR gave a good answer. In the former case, if the code would work, none of the shared_ptr you create would get deleted until the end of the program because they are stored in a global vector. In this case just keep it simple and use old style pointers and add them at the constructor and delete in destructor. For efficiency it's better to change the vector data type. E.g.,
#include<iostream>
#include<memory>
#include<unordered_set>
class A;
std::unordered_set<A*> alpha;
class A{
public:
A(): x(9)
{
alpha.insert(this);
}
~A(){
alpha.erase(this);
}
private:
int x;
};
Example test:
int main(){
std::shared_ptr<A> a= std::make_shared<A>();
std::cout << "Number of objects: " << alpha.size() << std::endl;
{
std::shared_ptr<A> a1= std::make_shared<A>();
std::shared_ptr<A> a2= std::make_shared<A>();
std::cout << "Number of objects: " << alpha.size() << std::endl;
}
std::cout << "Number of objects: " << alpha.size() << std::endl;
}
Number of objects: 1
Number of objects: 3
Number of objects: 1
class A
{
public:
A(int a, int b, int c)
:x(a), y(b), z(c)
{}
void display()
{
cout << "x is " << x << endl;
cout << "y is " << y << endl;
cout << "z is " << z << endl;
}
int x;
protected:
int y;
private:
int z;
};
class B : public A
{
public:
B(int x, int y, int z, int extra)
: A(x, y, z), num(extra)
{}
void display()
{
cout << "x is " << x << endl;
cout << "y is " << y << endl;
//cout << "z is " << z << endl;
}
private:
int num;
};
int main()
{
A yo1(1,2,3,);
B yo2(4,5,6,100); //<---
yo2.display(); //I want to print 1 2 3 100
return 0;
}
I have a simply inheritance here. Using inheritance, I want to get A's values and put it into B. How do I access the values of its data members from class A by created a B object? I created an object of class A and gave them the value 1,2,3. In the end, I want to print 1 2 3 100 by using class B's display function.
I understand how I can use the variables from class A but can I also grab their values?
you are confused with concept of inheritance,
B yo2(4,5,6,100);
during this there is separate copy of base class created for the object yo2 which has nothing to do with the object yo1
A yo1(1,2,3,);
the data members x,y,z will have 1,2,3 for yo1 and 4,5,6 for yo2
if you want the output to be
1 2 3 100
then create the object as :
B yo2(1,2,3,100);
you can modify your derived class as
class B : public A
{
public:
B(A& obj, int extra)
: A(obj.x, obj.y, obj.z), num(extra)
{}
void display()
{
A::display();
cout << "num is " << num << endl;
}
private:
int num;
};
and in main you can access as
int main()
{
A obj(1,2,3);
B objB(obj,100);
objB.display();
}
I think you might have misunderstood inheritance.
There is no way for yo2 to know about the values you have given to yo1.
The values yo2 have in A's variables are 4,5,6 respectively.
to illustrate inheritance a little you could rename the display methods "display_a" and "display_b" and then you could access them thus:
yo1.display_a(); // OK. prints values 1,2,3
yo1.display_b(); // Compile error.
yo2.display_a(); // OK. prints values 4,5,6
yo2.display_b(); // OK. prints values 4,5 from variables inherited from A.
To get what happens with the two "display" methods in your original code, look up overloading and the key-word "virtual". Also look up the operator ::
I hope this helps.
First, I think you have misunderstood what inheritance means and yo1 has nothing to do with yo2 at all. Second, you want to use B display function to display A object's members but you are lazy to construct B with argument 1,2,3 because A has constructed using those. Because A's y is protected and A's z is private, you must use a way to copy A object's members to B object if you want achieve your goal. So I think the rajenpandit's answer is right and useful for you.
For example, in this piece of code, if line [a] is commented out, the output is 0.
inh2.cpp
#include<iostream>
using namespace std;
class A {
public:
int x;
A() { x = 10; }
};
class B : public A {
public:
int x; // <--------- [a]
B() { x = 0; }
};
int main() {
A* ab = new B;
cout << ab->x << endl;
}
results from gcc
$ g++ inh2.cpp
$ ./a.out
10
$
I have two questions:
How does ab->x resolve to 10 in the above case? The object is of type class B, and thus should value to 0.
Why does commenting Line [a] change the behaviour of the code? My reasoning is that x would have anyways been inherited, which should result in same behaviour.
My reasoning for Q #1 above:
ab points to the memory location of an object of class B. It is a physical object in the sense that all the variables with their values are assigned memory.
Variable x within this object stores value 0.
When ab->x is done, ab tells us the memory location of the object, and we go look inside it to find that x is 0. So we should print 0.
Where am I wrong here?
Yes, it is of type B, but you are assigning it as a pointer to an A, and therefore it is using the x defined on A (as when we're dealing with a pointer to A, we don't know that B even exists, even though that's what you allocated).
When you comment out the line, during the construction phase, As constructor is called first, then Bs constructor, which sets x (in its base class) to 0. There is only one x at this point, and Bs constructor is called last.
Making a some small modifications:
#include <iostream>
using namespace std;
class A {
public:
int x;
A()
:x(10)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << x << std::endl;
}
virtual ~A() {}
};
class B : public A {
public:
int x; // <--------- [a]
B()
:A()
,x(0)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << x << std::endl;
}
};
int main() {
A* ab = new B;
cout << "ab->x: " << ab->x << endl;
cout << "ab->A::x " << ab->A::x << endl;
B* b = dynamic_cast<B*>(ab);
cout << "b->x: " << b->x << endl;
cout << "b->A::x " << b->A::x << endl;
cout << "b->B::x " << b->B::x << endl;
}
This gives you:
A
10
B
0
ab->x: 10
ab->A::x 10
b->x: 0
b->A::x 10
b->B::x 0
This demonstrates that:
ab->x refers to A::x because ab is of type A* and there is no such thing as a virtual variable. If you want polymorphism, you'll have to write a virtual int get_x() const method.
B::x hides A::x. This is a bad idea and should be avoided. Consider using a more meaningful name for your member variables and establish whether you can reuse the base class's variable before introducing a new one.
Casting to a B* allows you access to B's members as well as A's. This should be self-explanatory.