-1

In the following code although the instances of subclass are getting pushed on the stack of base class but while retrieving(top operation) an element and storing it in derieved class object, the compiler is generating an error.

#include <cstdio>
#include <stack>

using namespace std;

class base{};

class sub : public base{
public:
    int a;
    sub (int A){ a=A;}
};

int main(){
    stack<base> st;

    sub A = sub(10);
    sub B = sub(20);

    st.push(A);
    st.push(B);
    printf("%d\n", (int)st.size());

    sub C = (sub)st.top();

    return 0;
}

Error:

 In function ‘int main()’:  
24:22: error: no matching function for call to ‘sub::sub(base&)’  
24:22: note: candidates are:  
11:2: note: sub::sub(int)  
11:2: note:   no known conversion for argument 1 from ‘base’ to ‘int’  
8:7: note: sub::sub(const sub&)  
8:7: note:   no known conversion for argument 1 from ‘base’ to ‘const sub&’  

Please suggest any way by which I can typecast the retrieved base class object to derieved class.

sv_jan5
  • 1,543
  • 16
  • 42
  • Use something like `stack> st;` – πάντα ῥεῖ Feb 20 '16 at 11:24
  • 1
    For polymorphism you need pointers or references. And since you can't store references in a container you need to use pointers. As for casting a pointer to a base class to a pointer to the child class, search for and read about *downcasting*. – Some programmer dude Feb 20 '16 at 11:27
  • @ πάντα ῥεῖ I tried replacing the definition of stack with your's but it didn't help. Can you elaborate a bit on that? – sv_jan5 Feb 20 '16 at 11:32
  • Realistically, you can't. You need pointers or references. So this question, as asked, cannot be answered. – Peter Feb 20 '16 at 11:49

2 Answers2

2

A standard container like std::stack should store pointers to the base class which point to dynamically allocated sub-class objects. In modern C++, you are well-advised to automate the memory management for this, using std::unique_ptr.

std::unique_ptrs should be created with std::make_unique. A std::unique_ptr cannot be copied but only be moved. This happens automatically when you pass an unnamed temporary to the stack's push function.

std::unique_ptr (unlike std::shared_ptr) also requires a virtual destructor. But that should not be a problem, because the reason you are using a base class and a derived class in the first place should be that you have code which does not need to be aware of the derived type but just uses virtual functions of the base type. (If you just need to access the implementation of base in sub, then public inheritance is the wrong tool anyway.)

Here is a complete example (I've also fixed some other problems in your code):

#include <stack>
#include <memory>
#include <iostream>

// using namespace std; is bad practice --> removed

class base {
public:
    virtual ~base() {}
};

class sub : public base{
public:
    int a;
    sub (int A) : a(A) {} // initialisation list rather than assignment
};

int main(){
    std::stack<std::unique_ptr<base>> st;

    st.push(std::make_unique<sub>(10));
    st.push(std::make_unique<sub>(20));
    std::cout << st.size() << "\n"; // no more printf

    auto const& C = *(st.top()); // using C++11 auto

    // no return 0 necessary in main
}

Now, C is a reference of the base type.

If, for some reason, you really need to access the underlying sub, then you can do as follows:

auto const& C = dynamic_cast<sub const&>(*(st.top()));
std::cout << C.a << "\n";

It's ugly, but then the whole concept of assuming a concrete sub-class is typically a design flaw, so the ugliness of the code fits the ugliness of the concept.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
1

That's an error to expect, naturally because an object of the class base and another of the class sub are different to the compiler. When you equate an r-value, a, to another value, b, you're calling a's copy-constructor with b as an argument. By default, if you don't implement this in your class declaration, C++ will perform a per-member copy of b to your members in a. However, if a and b are of different types, what members will be copied is ambiguous to the compiler, even if one is derived from the other (as there's always chance there will be additional members in it, thus increasing the size and changing the structure of the class of the object).

As Joachim answered in the comments, for polymorphism to work, you need to deal with pointers or references. You can't use references because you can't have containers of references.

stack<base*> st;

sub A = sub(10);
sub B = sub(20);

st.push(&A);
st.push(&B);
printf("%d\n", (int)st.size());

sub *C = (sub*)st.top();
Aiman Al-Eryani
  • 709
  • 4
  • 19
  • 1
    The code is technically correct but quite dangerous. `st` outlives `A` and `B` and ends up containing dangling pointers. – Christian Hackl Feb 20 '16 at 12:09
  • But wait, are they not in the same scope? What are the situations this can happen accidentally? – Aiman Al-Eryani Feb 20 '16 at 12:11
  • Yes, I should have worded my comment more precisely. Let's say that the code can easily *evolve* such that the stack outlives `A` and `B`. For example, the stack could be returned from a function. – Christian Hackl Feb 20 '16 at 12:19
  • What's the best solution here then? Create the sub objects (A and B) on the heap and store smart unique_ptrs? I suppose that would clutter up the example code though... – Dan Aug 12 '20 at 10:49