C++ - Make pointer to superclass match subclass argument in function - c++

I've searched before asking but din't found anything working for my problem.
I would like to make a pointer to superclass (that really always refers to one of the subclasses) match a subclass argument (pointer or const reference) in a function.
Context : create an "advanced" calculator in c++.
Let me give you more details the classes being used in this issue of mine :
First we have the Literals :
class Literal {};
class IntegerLiteral : public Literal {};
class RealLiteral : public Literal {};
class RationalLiteral : public Literal {};
//....
We have a stack used to save the Literal objects by storing their adresses
// If st is instance of stack then :
st.top(); // returns a Literal*
And we have Operator objects that will interact with the stack by unstacking the correct numbers of Literal* (depending on the operator's arity), applying the operator on the Literal* objects and finally stack the result.
class Operator {
int n; // operator arity
public:
virtual void executeOperator(stack *st) = 0; //
};
One of the Operator subclass (for example) :
class PlusOperator : public Operator {
public:
virtual void execute(StackUTComputer *st) override {
Literal* arg1 = st->top();
Literal* arg2 = st->top();
Literal* result = applyOperator(arg1, arg2);
st->pop(); st->pop();
st->push(result);
}
Literal* execute(IntegerLiteral* a, IntegerLiteral* b) {
return new IntegerLiteral(a->getValue() + b->getValue());
}
Literal* execute(IntegerLiteral* a, RealLiteral* b) {
return new RealLiteral(a->getValue() + b->getValue());
}
Literal* execute(IntegerLiteral* a, RationalLiteral* b) {
return new RationalLiteral(
a->getValue() + (a->getValue()*b->getDenominator()),
b->getDenominator()
);
}
// ...
};
My purpose here (by overloading the function applyOperator) is to "magically" let the computer know which function call depending on the real type of Literal unstacked by the operator (the class Literal is abstract : the stack will always contain specifics Literal's subclasses).
But it does not work the way I want.
I mean that the call applyOperator(arg1, arg2) (with arg1 and arg2 being Literal*) is invalid because no functions match the signature.
I'm aware that I kind of use the c++ polymorphism int the other way that it's normally used (that is give a subclass argument to a function that take a superclass argument).
I don't know how to turn around my architecture in order to properly use the polymorphism et maybe there is some syntax helpful solution in order to make my idea work.
Either way, I'm grateful for your help !!
Raphael.

There is a way to do it with polymorphism as intended (without dynamic_cast):
#include <iostream>
#include <memory>
#include <string>
struct IntegerLiteral;
struct RealLiteral;
struct Literal {
virtual void add(const Literal &) = 0;
virtual void add(const IntegerLiteral &) = 0;
virtual void add(const RealLiteral &) = 0;
virtual void add_to(Literal &) const = 0;
virtual void add_to(IntegerLiteral &) const = 0;
virtual void add_to(RealLiteral &) const = 0;
virtual std::ostream &print(std::ostream &os) const = 0;
virtual ~Literal() = default;
};
std::ostream &operator<<(std::ostream &os, const Literal &l) {
return l.print(os);
}
struct IntegerLiteral : Literal {
IntegerLiteral(int i)
: i(i) {}
int i = 0;
void add(const Literal &other) override {
//now we know one operand is an IntegerLiteral and can pass on that information to the other Literal
other.add_to(*this);
}
void add(const IntegerLiteral &other) override {
i += other.i;
}
void add(const RealLiteral &other) override;
void add_to(Literal &other) const override {
other.add(*this);
}
void add_to(IntegerLiteral &other) const override {
other.i += i;
}
void add_to(RealLiteral &other) const override;
std::ostream &print(std::ostream &os) const override {
return os << i;
}
};
struct RealLiteral : Literal {
RealLiteral(double d)
: d(d) {}
double d = 0;
void add(const Literal &other) override {
other.add_to(*this);
}
void add(const IntegerLiteral &other) override {
d += other.i;
}
void add(const RealLiteral &other) override {
d += other.d;
}
void add_to(Literal &other) const override {
other.add(*this);
}
void add_to(IntegerLiteral &other) const override {
//now we know both operands and can do the calculation
other.i += d;
}
void add_to(RealLiteral &other) const override {
other.d += d;
}
std::ostream &print(std::ostream &os) const override {
return os << d;
}
};
void IntegerLiteral::add(const RealLiteral &other) {
i += other.d;
}
void IntegerLiteral::add_to(RealLiteral &other) const {
other.d += i;
}
int main() {
std::unique_ptr<Literal> l1 = std::make_unique<RealLiteral>(3.14);
std::unique_ptr<Literal> l2 = std::make_unique<IntegerLiteral>(42);
l1->add(*l2);
std::cout << *l1 << '\n';
}
DEMO
You need a ton of code to make this work and it gets quadratically worse with every Literal you add and twice as bad with every operator. Also if you forget to override a function you are likely to get an infinite loop and a stack overflow at run time.
A much better approach (easier to write and faster to run) would be to just use double or BigNum for everything and not bother with polymorphism.

You are mixing different concepts, which are ad hoc polymorphism (overloads) and subtype polymorphism, which in is implemented through late binding of methods through virtual tables.
Basically what happens is that the compiler chooses which overloaded method to call at compile time, not at runtime. This makes impossible what you are trying to do without using RTTI.
The compiler is not able to determine which will be the type of the two Literal instances, and C++ supports only early binding when dealing with non virtual methods. The only thing that it can deduce at compile time is the fact that both arguments are of type Literal* so it looks for that overload only.
You need a sort of dynamic switch to do what you want, which can be obtained through the use of dynamic_cast (or similar hand made solutions).

Related

derived class reusing base class operations

I have a large class, Base, that implements several different binary operations, some overloading the operators like *=, *, / etc, and some extra ones. The typical return type involves Base explicitly, for example:
class Base {
private:
std::vector<unsigned int> _arr;
public:
// These operations do something with _arr
Base& operator *= (const Base& rhs);
friend Base operator *(Base lhs, const Base& rhs);
std::vector<Base> myoperation(const Base& rhs);
};
I have a derived class, Derived, which simply adds extra structure, so it looks like this:
class Derived : public Base {
private:
std::vector<int> _arr_derived;
public:
// This operation does something with _arr and _arr_derived;
Derived& my_derived_operation(const Derived& rhs);
// These operations are exactly the same implementation as the one in Base!
Derived& operator *= (const Derived& rhs) {
Base::operator*=(rhs);
return *this;
}
friend Derived operator *(Derived lhs, const Derived& rhs) {
lhs *= rhs;
return lhs;
}
std::vector<Derived> myoperation(const Derived& rhs) // <---- what to do here?
};
What do I need to do with the operation myoperation? That returns a vector. There is no extra logic on all operations that are inherited, the only difference is in the return type. Is there any way to avoid the code duplication? Even the declaration of the operations is bothersome.
I thought perhaps defining the base operations as template functions returning the same type as the argument, and requiring the template parameter to be a derived class:
class Base {
// on C++20
template<class C> requires std::is_base_of_v<Base,C>
C& operator*=(const C& rhs);
}
Does this work? Even if it does, is there a better mechanism?
Edit to reply to Remy Lebeau's comment: I want to emphasize that all operations that appear both in Derived and in Base are meant to be the same, there is not extra logic except the returning type. The example of operator *= already shows this, just calling the Base version. A possible implementation, albeit stupid, of what I mean by myoperation could be this:
std::vector<Base> Base::myoperation(const Base& rhs) {
std::vector<Base> ret{};
ret.push_back(rhs*rhs);
return ret;
}
std::vector<Derived> Derived::myoperation(const Derived& rhs) {
std::vector<Derived> ret{}
ret.push_back(rhs*rhs);
return ret;
}
With the templated version I could write only
class Base {
teplate<class C> requires std::is_base_of_v<Base,C>
auto myoperation(const C& rhs) {
std::vector<C> ret;
ret.push_back(rhs*rhs);
return ret;
}
};
And that's what I meant by the templated solution above, so that I do not need to even declare myoperation on Derived.
I went with the templated version, although using pointers is standard in polymorphism, I have too many vector valued operations and are complicated enough to change the logic, and also wouldn't want to have to deal with recasting to Derived classes when necessary. Templating also has the advantage that no code needs to be written on the derived classes. So on base all operations that transform the object in place are left as they were and the ones that produce new ones are templated. I appreciate if I could be pointed to pitfalls of this approach
#include <iostream>
#include <vector>
class Base {
int _a;
public:
Base(int a) : _a{a} {};
Base& operator *= (const Base& rhs) {
_a *= rhs.a();
return *this;
}
template <class C> requires std::is_base_of_v<Base,C>
friend C operator *(C lhs, const Base& rhs) {
lhs *= rhs;
return lhs;
}
template <class C> requires std::is_base_of_v<Base,C>
std::vector<C> myop (const C& rhs) {
std::vector<C> ret {};
ret.push_back(rhs*rhs);
return ret;
}
int a() const { return _a; }
};
class Derived : public Base {
int _b;
public:
Derived(int a, int b) : Base{a}, _b {b} {}
int b() const {return _b;}
};
int main() {
Derived C{9,5};
Derived D{4,7};
auto E = C*D;
auto F = D.myop(C);
std::cout << E.a() << ", " << E.b() << std::endl;
std::cout << F.front().a() << ", " << F.front().b() << std::endl;
return 0;
}
OUTPUT:
36, 5
81, 5

How to properly rewrite with templates this C++ code that uses inheritance

I have a C++ code that currently looks like this: there is a class hierarchy to do perform some comparison and a list class that uses it. Which comparison operation to use is determined at runtime based on some schema object. Here is the structure:
class A{
bool doComparison(const string& s1, const string& s2) const=0;
}
class B: public A{
bool doComparison(const string& s1, const string& s2) const {
...
}
}
class C: public A{
bool doComparison(const string& s1, const string& s2) const {
...
}
}
template <class, S>
public FancyList{
shared_ptr<A> z_;
vector<S> v;
FancyList(shared_ptr<A> z) : z_(z);
void DoSmth(){
....
z_->doComparison(arg1, arg2);
}
}
typedef FancyList<string> FancyStringList;
// Determine which comparison to use at runtime
shared_ptr<A> c = nullptr;
switch(type):
case int:
c = make_shared<B>();
break;
case double:
c = make_shared<B>();
break;
FancyStringList l(c);
l.push_back("stuff");
C# used to be my main language so this code seemed ok to me. But I was told that the problem with this approach is that it uses virtual functions so there is a slight overhead in a method call. What is the proper C++-way of reorganizing this code so there is no need to have this class hierarchy and no need to use virtual functions?
Contrary to what you want, the overhead of virtual function is unavoidable because the decision of which actual function is called is made in runtime.
If the decision is always made in runtime, the compiler cannot hard-code the function call into the generated machine code. It has to be a indirect function call: to use a pointer to point to a function, and to dereference the pointer before the function call. Virtual function is just one way to do indirect function call.
Template is a way tell the compiler to generate code during compile-time. All template can do is to not introduce overhead when the decision is made during compile-time. It can't help you remove works that must be done in runtime.
If you are still interested in using template, you may consider having the comparator as a template parameter.
template <class T, class Comparator>
class MyList
{
std::vector<T> vec;
Comparator comp;
public:
void do_thing(const T& a, const T& b)
{
vec.push_back(a);
vec.push_back(b);
bool x = comp(vec[0], vec[1]); // for example
std::cout << x;
}
};
In the comparator class, overload the function call operator.
class Compare1
{
public:
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return lhs < rhs;
}
};
class Compare2
{
public:
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return lhs.size() < rhs.size();
}
};
int main()
{
MyList<std::string, Compare1> myli1;
myli1.do_thing("a", "b");
MyList<std::string, Compare2> myli2;
myli2.do_thing("c", "d");
}
You can even hide indirect function call behind comparator class. But it does not remove the overhead.
class A
{
public:
virtual bool doComparison(const std::string& s1, const std::string& s2) const=0;
virtual ~A() = default;
};
class PolymorphicComparator
{
private:
std::shared_ptr<A> comp;
public:
PolymorphicComp(std::shared_ptr<A> c) : comp(c) {}
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return comp->doComparison(lhs, rhs);
}
};

Sorting list of shared pointers

Given the class
class objects {
public:
bool compareArea (const objects& obj) const { return this->area < obj.area; }
private:
double area;
};
I want to sort a
list<shared_ptr<objects>> myObjects;
I cannot use a lambda (since my toolchain's C++11 support is incomplete). Thus, I tried the following:
using namespace placeholders;
myObjects.sort(bind(&objects::compareArea,_1,_2));
This line is called from another file (not from a class member!). The problem is, that compareArea requires two objects as input. But I give two shared pointer to objects to it. Is there an easy way of how to include the dereferencing of the pointers into the sort-call? I want the objects::compareArea(..) function to stay as it is. I do not want this kind of solution
bool compareArea (const shared_ptr<objects>& ptr1, const shared_ptr<objects>& ptr2) {
return ptr1->area > ptr2->area;
}
// in same source-file:
myObjects.sort(bind(compareArea,_1,_2));
where compareArea is no member-function of objects. Actually an operator overloading of < would be my favourite solution.
I would strongly suggest that you never store any kind of pointer in a container.
Instead, make a handle class which supports the required arithmetic and comparison operators.
It makes for code that's easier to reason about:
class objects {
public:
objects(double w, double h) : area(w * h) {}
bool operator<(const objects& r) const { return this->area < r.area; }
private:
double area;
};
struct object_handle
{
object_handle(shared_ptr<objects> const& ptr) : ptr_(ptr) {}
static object_handle create(double w, double h) { return make_shared<objects>(w,h); }
bool operator < (object_handle const& r) const {
return *ptr_ < *r.ptr_;
}
shared_ptr<objects> ptr_;
};
int main() {
std::vector<object_handle> mylist;
mylist.push_back(object_handle::create(10, 7));
mylist.push_back(object_handle::create(2, 5));
std::sort(mylist.begin(), mylist.end());
}
Lambdas are just syntactic sugar for a class with operator(), so you can very easily write one directly (especially if you don't need captures):
struct Comparator
{
bool operator() (const shared_ptr<objects> &lhs, const shared_ptr<objects> &rhs) const
{
return lhs->compareArea(*rhs);
}
};
myObjects.sort(Comparator());

trouble with operator overloading in baseclass

Hi I'm having some trouble with inhertance and operator overloading and I'm hoping you guys can give me some clarity.
I have the following classes:
template<typename Type>
class Predicate{
public:
Predicate() {};
virtual ~Predicate(){};
virtual bool operator()(const Type & value) = 0;
virtual bool operator()(const Type * value){ //<-- this is the operator thats not working
return (*this)(*value);
};
};
template<typename Type>
class Always : public Predicate<Type>{
public:
bool operator()(const Type & value){return true;}
~Always(){};
};
Now I want all my predicates to accept both references and pointers, but when I test the classes in:
int main(){
Always<int> a;
int i = 1000;
a(&i);
system("pause");
return 1;
}
I receive the following error:
test.cpp: In function 'int main()':
test.cpp:10:6: error: invalid conversion from 'int*' to 'int' [-fpermissive]
a(&i);
^
In file included from test.cpp:2:0:
predicates.h:22:7: error: initializing argument 1 of 'bool Always<Type>::operator()(const Type&) [with Type = int]' [-fpermissive]
bool operator()(const Type & value){return true;}
This is because when you are declaring:
bool operator()(const Type & value){return true;}
in the subclass, you are hiding/shadowing any other overload of the operator in the superclass.
If you add:
using Predicate<Type>::operator();
Live demo
in the subclass, everything will work fine.
On a side note, I think that allowing both const& and const* is a design smell. You should just allow the const& version and let the user of your class do *ptr if they have a ptr pointer.
Templates and operator overloading obfuscate the real problem here. Look at this small piece of code which yields the same error:
void f(int &);
int main()
{
int *ptr;
f(ptr);
}
The compiler won't let you pass a pointer where a reference is expected. This is what you try to do with your derived class. As you operate on a concrete Always, the base versions of operator() are not considered.
Look how the situation changes when you operate instead on a pointer (or reference) to the base class:
int main(){
Predicate<int> *ptr = new Always<int>;
int i = 1000;
(*ptr)(&i);
delete ptr;
}
This compiles fine because the base-class operators are now considered for overload resolution. But this is just to make you understand the problem better. The solution is to apply the Non-Virtual Interface Idiom. Make your operators non-virtual and implement them in terms of private virtual functions:
template<typename Type>
class Predicate{
public:
Predicate() {};
virtual ~Predicate(){};
bool operator()(const Type & value) { return operatorImpl(value); }
bool operator()(const Type * value) { return operatorImpl(value); }
private:
virtual bool operatorImpl(const Type & value) = 0;
virtual bool operatorImpl(const Type * value) {
return (*this)(*value);
}
};
template<typename Type>
class Always : public Predicate<Type>{
public:
~Always(){};
private:
bool operatorImpl(const Type & value){return true;}
};

Implementing operator< on abstract base class

I have a type hierarchy, and I'm not sure of a clean / good way to implement operator< and operator==.
Essentially, I already have this:
class Parent {
public:
virtual ~Parent() {}
};
class A : public Parent { int data; };
class B : public Parent { double data; };
class C : public Parent { std::string data; };
bool operator==(A const & lhs, A const & rhs) { return lhs.data == rhs.data; }
bool operator< (A const & lhs, A const & rhs) { return lhs.data < rhs.data; }
bool operator==(B const & lhs, B const & rhs) { return lhs.data == rhs.data; }
bool operator< (B const & lhs, B const & rhs) { return lhs.data < rhs.data; }
bool operator==(C const & lhs, C const & rhs) { return lhs.data == rhs.data; }
bool operator< (C const & lhs, C const & rhs) { return lhs.data < rhs.data; }
What I'd like to implement as well, is this:
bool operator==(Parent const & lhs, Parent const & rhs) { ... }
bool operator< (Parent const & lhs, Parent const & rhs) { ... }
I've currently implemented it by doing:
bool operator==(Parent const & lhs, Parent const & rhs) {
try {
return dynamic_cast<A const &>(lhs) == dynamic_cast<A const &>(rhs);
} catch(std::bad_cast const & e) {
}
try {
return dynamic_cast<B const &>(lhs) == dynamic_cast<B const &>(rhs);
} catch(std::bad_cast const & e) {
}
try {
return dynamic_cast<C const &>(lhs) == dynamic_cast<C const &>(rhs);
} catch(std::bad_cast const & e) {
}
assert(typeid(lhs) != typeid(rhs));
return false;
}
But this just seems awful. Is there a cleaner way of going about this?
For comparisons of complex types, you may find Double Dispatch useful.
If your types are very simple, it is sometimes effective to roll them all into one. In the example of 3 unsigned variants, it would likely be better to just use one type to accommodate all sizes, and to avoid dynamic dispatch and more complicated graphs of types.
Applied to original question; where A, B, and C all used unsigned types:
well, one quick and dirty approach would be:
class Parent {
protected:
virtual ~Parent() {}
public:
bool operator<(const Parent& pOther) const {
return this->as_uint64() < pOther.as_uint64();
}
// ...
private:
// using a type which accommodates all values
virtual uint64_t as_uint64() const = 0;
};
and then deriving from Parent would take the form:
class A : public Parent {
// ...
private:
virtual uint64_t as_uint64() const { return this->data; }
private:
uint16_t data;
};
then Parent could simply define all comparators, and all Parent types would be comparable.
Use a virtual comparator for single dispatch and dynamic_cast for type casting:
class ABC_base {
public:
virtual ~ABC_base() {}
bool operator < (ABC_base const & rhs) const {
return this->comparator(rhs) < 0;
}
protected:
virtual int comparator (ABC_base const &) = 0;
};
class ABC : public ABC_base {
protected:
virtual int comparator(ABC_base const & rhs) const {
try {
return my_comparator(dynamic_cast<ABC const&>(rhs));
// Run-time cast failed - use double dispatch as fallback
} catch (std::bad_cast&) {
return -rhs.comparator(*this);
}
}
private:
int my_comparator(ABC const & rhs) const {
if (data < rhs.data)
return -1;
if (data == rhs.data)
return 0;
if (data > rhs.data)
return 1;
}
T data;
};
Here's how the code works:
The base class's operator < is called, which uses dynamic lookup to find the comparator. It checks the returned value to see if it's lesser.
The derived class's comparator attempts to downcast the base class reference so that comparison can be done on the derived class's members.
Why the base class reference, instead of using the derived class reference?
Virtual dispatch would not work otherwise due to incorrect function signature.
Should the downcast succeed, it calls the non-virtual private comparator. Otherwise, it uses virtual dispatch again to do (rhs ? *this) and negates the result to compensate for the inverted ordering.
Why not have the cast and comparison in the one virtual function? It will make the code messier since the function will do two things: casting and comparing. Hence, there's a private comparator function. Should you want to use the base function in a derived class, along the lines of class ABC_der : public ABC, call ABC::comparator(static_cast<ABC const&>(rhs)). The use of Base:: forces static dispatch so you don't have to expose the helper comparison function.
Right now, this and rhs are of the same type, so we can finally do the actual comparison. A chain of if statements is used to return a value conformant to Java's Comparable and C's qsort() semantics.