trouble with operator overloading in baseclass - c++

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;}
};

Related

Operator overloading with template question

I'm unable to recognize the following forms of operator overloading, specifically with the template parameter involved. I found this while reading an article on nullptr. I do not see these forms on cppreference overloading page either.
Can anyone explain these forms of overloading and what they are doing?
Thanks
struct nullptr_t
{
void operator&() const = delete; // Can't take address of nullptr
template<class T>
inline operator T*() const { return 0; }
template<class C, class T>
inline operator T C::*() const { return 0; }
};
nullptr_t nullptr;
Starting simpler:
struct A {
operator int() {return 3;}
};
void function() {
A aobject;
int value = aobject; //uses A::operator int()
//value is now 3
}
operator int is a curious member function that allows the struct to be converted to an int. It's very curious in that it's the only case in C++ that uses the return type in order to resolve which overloaded function to call, including that it can resolve template types.
struct A {
operator int*() {return 0;}
};
void function() {
A aobject;
int* value = aobject; //uses A::operator int()
//value now holds the value 0 (NULL)
}
This is the same thing, but now A can be converted to an int*. It is otherwise self explanatory.
struct A {
template<class T>
operator T*() { return 0; }
};
void function() {
A aobject;
short* value = aobject; //uses A::operator T*<int>()
//value now holds the value 0 (NULL)
}
By making A::operator T*() a template method, we can make our class able to be converted to a pointer to any type. This expands the options for what you can convert to. operator T C::*() { return 0; } is similar, but also allows conversion to pointers to any member of any class, which is very rare and advanced.

Can I call the subclass constructor from my superclass?

I want to know if I can return a subclass object through an overloaded operator from my superclass.
#include <stdio.h>
#include <iostream>
using namespace std;
struct AndSpecification;
struct Specification{
virtual bool is_satisfied(int i) = 0;
AndSpecification operator&& (Specification & other){
return AndSpecification(*this, other);
}
};
struct Specification1 : Specification{
int k;
Specification1(int k) : k(k){}
bool is_satisfied(int i){
if (i > k)
return true;
return false;
}
};
struct Specification2 : Specification{
int k;
Specification2(int k) : k(k){}
bool is_satisfied(int i){
if (i < k)
return true;
return false;
}
};
struct AndSpecification : Specification{
Specification& first;
Specification& second;
AndSpecification(Specification& first, Specification& second) : first(first), second(second){}
bool is_satisfied(int i) override{
return first.is_satisfied(i) && second.is_satisfied(i);
}
};
I think that the result is that I can't use the constructor of my subclass because it is not yet defined. The error messages are:
main.cpp: In member function ‘AndSpecification Specification::operator&&(Specification&)’:
main.cpp:20:56: error: return type ‘struct AndSpecification’ is incomplete
AndSpecification operator&& (Specification & other){
^
main.cpp:21:45: error: invalid use of incomplete type ‘struct AndSpecification’
return AndSpecification(*this, other);
Your incomplete forward class declaration cannot be used in this manner until the class is fully defined. Incomplete (forward) class declaration can be used in certain cases, but this is not one of them.
A C++ compiler reads the source in order, from start to finish. When it sees your operator, it has no idea what this mysterious class is, that it's returning. It has not been defined yet. It only gets defined later, in the header/source file.
You need to declare the class method, and then define it only after the class it's returning is fully defined:
// ...
struct Specification{
virtual bool is_satisfied(int i) = 0;
AndSpecification operator&& (Specification & other);
};
// After AndSpecification is declared, later:
inline AndSpecification Specification::operator&& (Specification & other){
return AndSpecification(*this, other);
}
As an alternative to inline, put the definition of the operator method into one of the translation units.
Whenever the compiler must know the size of a type, it must be defined. A declaration is not enough for constructing a type.
In your case, the simple fix is to make operator&& a free function and move it to the bottom:
AndSpecification operator&& (Specification & left, Specification & right){
return AndSpecification(left, r)ight;
}
In my opinion, free binary operators are better than member functions.
You've implemented an inline function definition before completing the definition of one of the classes you're using in the function. The compiler knows there's a struct AndSpecification but it doesn't know that the particular constructor you're using exists. Declare your method in the class but don't define it until after the definition of AndSpecification.
struct Specification{
virtual bool is_satisfied(int i) = 0;
AndSpecification operator&& (Specification & other);
};
struct AndSpecification : Specification { ... }
inline Specification::operator&& (Specification & other) {
return AndSpecification(*this, other);
}

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);
}
};

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

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).

Operator overloading and inheritance (keeping the same type)

I have a bit of a problem with operator overloading and inheritance in C++.
Quick sketch:
class A {
public:
A operator+ (const A &b) const { ... }
};
class B : public A {
...
};
Now suppose I have two instances of B, x and y. If I add them I will get a thing of type A, however I want it to be of type B.
What is the best way of accomplishing this (aside from reimplementing them in class B) ? CRTP?
You can implement operator+ outside of the class as a template:
template<class type> type operator+(const type& left, const type& right)
{
type toReturn;
toReturn.value = left.value + right.value;
return toReturn;
}
class A {
private:
int value;
template <class type>
friend type operator+<type>(const type& left, const type& right);
};
class B : public A {
};
int main()
{
B test1, test2;
B test3 = test1 + test2;
}
This approach has certain down-sides. The compiler will aggressively try to instantiate the operator+ template for types which you don't want to define operator+, so be aware of that.