I have a stack of classes with pure virtual members, it'll be populated by derived non-abstract classes. I'm getting the error:
Error C2259 'ABC': cannot instantiate abstract class TEMP c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\xmemory0 879
This error can be solved by using stack<ABC*>
, however heap memory access is slower than stack memory, so I'm thinking about rewriting the base class ABC with no pure virtual members at all.
Would there be any drawbacks from this (except the possible human error of whoever might use this code)?
Is there a way I can create a stack of classes with pure virtual members on the stack? Or, maybe, am I too paranoid about using the heap? The class (in the original code) would be accessed very frequently.
Simplified version of the code below:
#include <iostream>
#include <stack>
class ABC {
public:
ABC(int& a) : m_a(a) {}
~ABC() {}
virtual void do_something() = 0;
int m_a;
};
class DEF : public ABC {
public:
DEF(int& a) : ABC(a) {}
void do_something() override;
~DEF() {}
};
void DEF::do_something() {
std::cout << "Hi!\n";
}
int main(int argc, char* argv[]) {
int x = 123;
std::stack<ABC> s;
s.push(DEF(x));
}
CodePudding user response:
In this call
s.push(DEF(x));
the temporary object of the type DEF
is implicitly converted to an object of the type ABC
. So if to call the virtual function then the virtual function of the class ABC will be called.
You can use the polymorphism when you use pointers or references.
Here is your updated program.
#include <iostream>
#include <stack>
class ABC {
public:
ABC(int& a) : m_a(a) {}
~ABC() {}
virtual void do_something()
{
std::cout << "Bye!\n";
};
int m_a;
};
class DEF : public ABC {
public:
DEF(int& a) : ABC(a) {}
void do_something() override;
~DEF() {}
};
void DEF::do_something() {
std::cout << "Hi!\n";
}
int main()
{
int x = 123;
std::stack<ABC> s;
s.push(DEF(x));
s.top().do_something();
}
The program output is
Bye!
As you can see there is object slicing.
CodePudding user response:
You can't have a container (of which stack is an example) of objects with virtual members at all (pure or not) and maintain the dynamic behavior. You can have a container of pointers to such objects and maintain the dynamic behavior, but not such objects themselves.
The time to use pure virtual is when the base class doesn't have a reasonable implementation available at all. Think of standard types like the stream buffers, the base simply defines an interface but there really isn't anything for the base to do for many operations. Only a derived type knows what it is supposed to do.