Virtual-like friend functions? - c++

I want to create interface like
class Scalar {
public:
Scalar() {}
virtual ~Scalar() {}
//virtual members operators
virtual Scalar& operator+() const = 0;
virtual const Scalar operator-() const;
virtual Scalar& operator=() = 0;
virtual Scalar& operator+=() = 0;
//...
};
I intend also to use some friend functions, for example:
friend const Scalar operator+(const Scalar&, const Scalar&);
But there is a problem when I derive the abstract class, and create derived class, say:
class RealNumber: public Scalar {
public:
friend const RealNumber operator+(const RealNumber&, const RealNumber&);
//some definitions...
};
According to this logic, I would need to define a new overload of friend operator+ for every new class derived from Scalar. Is there some way to solve this problem and avoid declaring these friends in all the derived classes?

Is this your problem ?
I understand that your problem is that your two friends refer to totally different functions, since they have a different signature:
friend const Scalar operator+(const Scalar&, const Scalar&);
friend const RealNumber operator+(const RealNumber&, const RealNumber&);
Worse, the choice of a class external friend will not be polymorphic: the right friend will be chose based on the compile-time type.
How to solve it ?
First of all, instead of using an outside overloaded friend, you could consider overriding the operator of the class itself (keeping the signature identical).
However this has two major challenges:
it is almost impossible to return a reference from arithmetic operator, unless you'd accept side-effects, which would then make your operator behave differently than expected.
you'd need to cope with combining different kind of scalars: what if you'd have to add a Scalar to a RealNumber ? This would require a double dispatch to be implemented to cope with all the possible combination.
So, dead-end ?
No, there are two other alternatives, depending on your real problem:
Do you really want to combine arithmetic type dynamically at run-time ? If yes, you need to go away from the C++ operator overriding approach, and implement an expression evaluator, using the interpreter pattern.
If not, consider to use a template based design, so that the compiler choses at compile-time the appropriate specialisation.
Or suffer with the many possible friends and their combination of parameter types.

You may not be able to create virtual friend functions, but you can create virtual operators (even operator + could be done this way).
Consider the following code: WARNING: THIS IS NOT GOOD DESIGN AT ALL
#include <iostream>
using namespace std;
class AA {
private:
int a;
public:
AA(int a): a(a) {};
inline int getA() const { return a; };
virtual AA operator +(const AA &a) {
AA res(this->getA() + a.getA());
return res;
}
};
class BB: public AA {
public:
BB(int a): AA(a) {}
virtual AA operator +(const AA &a) {
AA res(this->getA() - a.getA());
return res;
}
};
int main() {
BB tmp(1);
AA& a = tmp;
AA b(7);
cout << (a + b).getA();
return 0;
}
When I was writing this code, I found that a lot of flaws could be induced (like the + operator that really does substraction instead, also what if the second operand was BB instead of the first one ??)
So, about your problem, you want Scalars. So you can do the following approach:
#include <iostream>
using namespace std;
// Here, Scalar acts as an abstract class, all its goal is to convert your
// class type into some calculable value type (e.g. you can use T as double)
template <typename T>
class Scalar {
public:
// Converter function is abstract
virtual operator T() = 0;
};
class AA: public Scalar<double> {
private:
double a;
public:
inline double getA() {return a;};
AA(double a): a(a) {}
// Implements the converter function in Scalar, T in scalar is mapped
// to double because we did Scalar<double>
virtual operator double() {
return a;
}
};
class BB: public Scalar<double> {
private:
int a;
public:
inline double getA() {return (double)a;};
BB(int a): a(a) {}
virtual operator double() {
return (double)a;
}
};
int main() {
BB tmp(1);
AA b(7);
// Here, it is easy for us just to add those, they are automatically converted into doubles, each one like how it is programmed.
cout << (b + tmp);
return 0;
}

Related

How to declare simple conversion operator T() in templated base class

I've been working on some class hierarchy with a goal to have a collection of classes that encapsulate primitive types (AdvancedInt, AdvanceDouble, etc.) and give them some additional behavior when accessing their underlaying values, through conversion operator and assignment operator. I can't do this with getters and setter as I can't change the original code and the way it access them, so my only choice is operator overloading.
The problem I ran into is with the templated class that defines the conversion operator which gives me a compiler error.
Here is the code that illustrates the problem
#include <string>
class Base {
public:
Base() = delete;
Base(std::string s) : name(s) {
//Some extra logic
}
~Base() {
//More custom logic
}
virtual std::string get_name() const final { //Final on purpose
return name;
}
private:
const std::string name;
};
template <typename T, class C> class Serializable :public Base { //Poor man's interface (but not quite)
public:
Serializable() = delete;
Serializable(std::string name) : Base(name) {
}
operator T() const {
//Some extra 'getter' logic
return value;
}
C& operator=(const T& val) {
//Some extra 'setter' logic
value = val;
return (C&)*this;
}
virtual void serialize() = 0; //This has to be pure virtual
private:
T value;
};
class AdvancedInt final : public Serializable<int, AdvancedInt> { //This is the actual complete class
public:
AdvancedInt(std::string name) : Serializable(name) {
//Nothing here, but needed for the special constructor logic from AbstractBase
}
void serialize() override {
//Some logic here
}
};
int main()
{
AdvancedInt adv{"foo"};
int calc = adv;
calc += 7;
adv = calc; //error C2679 (msvc) | binary '=': no operator found which takes a right-hand operand of type 'int' (or there is no acceptable conversion)
return 0;
}
Now aside from the (probably) questionable practice of passing AdvancedInt to the template of its own base class and it subsequently knowing that it's part of some derived class and implementing its logic (although any feedback on this is welcome), my main question is, what am I doing wrong here?
The C& operator=(const T& val) compiles fine when defined as pure virtual, but that enforces the implementation to be in the derived class, and when implemented there with T and C replaced by their corresponding types it works just fine, so the signature is logically sound, but probably not in the correct place(?). From what I've found on cppreference.com, the simple assignment operator is the only assignment operator that cannot be defined outside of class definition. Is this the reason why this code doesn't compile? And if so, is declaring it as pure virtual a way to go?
With adv = calc we look for operator= from AdvancedInt and found (implicit):
AdvancedInt& operator=(const AdvancedInt&);
AdvancedInt& operator=(AdvancedInt&&);
and look-up stops there.
Adding:
using Serializable<int, AdvancedInt>::operator=;
would allow to consider also that overload.
And that fixes your issue.
Demo.

Specify priority between implict conversions

I am trying to find a way to specify a hierarchy of implicit conversions between different types.
Suppose I have two types and a function overload for each:
struct A{};
struct B{};
void f(A const& a){}
void f(B const& b){}
Now I have another class that it is implicitly convertible to both A and B
class C{
A to_A() const{return A{} ;}
B to_B() const{return B{};}
operator A() const{return to_A() ;}
operator B() const{return to_B();}
};
As it is, I cannot use f directly because of ambiguity.
int main(){
C c;
f(c); // ambiguous, convert c to a, o c to b??
}
Let's also say that a conversion to B is more sensible given the option.
Is there way to specify in struct C one of the two (A or B) as the preferred conversion?, so that main compiles and is equivalent to f(c.to_B());
Full code here: https://godbolt.org/z/xvz71qEhK
Possible near solutions I discarded:
One obvious way is to make one conversions (to A) explicit, but I want that both conversion are implicit. Because there are other functions (not overloaded like f) where both conversion can be implicit.
At the place of call make the conversion explicit, main(){f(c.to_B());} The problem is that I am using this in generic template functions where the template parameter can be A, B or C.
For every ambiguous overload make a new overload f(C const& c){return f(c.to_B());}, the problem is that I have to do this for every overloaded functions that can take A or B and I have many of them. I can have tens of f-like functions, some of them with more than one argument (exploding number of combinations).
What I tried so far: I though that defining a hierarchy would help to select the preferred conversion, and that the operators of the leaf class would have preference, but it didn't remove de ambiguity.
https://godbolt.org/z/fYj7PP5GE
template<class CRTP>
struct base_to_A{
operator A() const{
return static_cast<CRTP const&>(*this).to_A() ;
}
};
class C : public base_to_A<C>{
A to_A() const{return A{};}
B to_B() const{return B{};}
public:
operator B() const{return to_B();}
};
Playing with public/protected/private didn't help.
Use variants in the API, and dispatch to template implementations if needed.
Have a conversion function that knows which you prefer.
void f(std::variant<A,B,C> var1, std::variant<A,B,C> var2){
return std::visit[&](auto& v1, auto& v2){
f_impl(v1,v2);
}, prefer_variant_convert<A,B>(var1), prefer_variant_convert<A,B>(var2) );
}
we take in variants, we run code to convert them to preferred variant types in order, then we generate exponential amounts of code to unnpack the variants.
Or, template version:
void f(auto var1, auto var2){
return f_impl( prefer_convert<A,B>(var1), prefer_convert<A,B>(var2) );
}
the prefer_convert<Ts...>(T0) returns T0 if it is in Ts..., otherwise the first of the Ts that T0 can convert to. It shouldn't be hard to write.
This doesn't answer the question in general, it is only in particular case and considering a certain design.
A partial solution that works in some designs:
If C can be implemented in terms of B alone and publicly, the conversion (actually a cast to B) will be preferred:
#include <cstdio>
struct A{};
struct B{};
void f(A const& a){std::puts("A");}
void f(B const& b){std::puts("B");}
class C : public B{
A to_A() const{return A{} ;}
// B to_B() const{return *this;} // not used
public:
operator A() const{return to_A() ;}
// operator B() const{return to_B();} // not needed, will never be called anyway
};
int main(){
C c;
f(c); // preferres B
}
https://godbolt.org/z/nnMPGbjeM

copy and swap idiom with pure virtual class

I am trying to implement virtual class with pure virtual method and 'copy and swap' idiom, but I've encountered some problems. Code won't compile because I am creating instance in the assign operator of the class A which contains pure virtual method.
Is there a way how to use pure virtual method and copy and swap idiom?
class A
{
public:
A( string name) :
m_name(name) { m_type = ""; }
A( const A & rec) :
m_name(rec.m_name), m_type(rec.m_type) {}
friend void swap(A & lhs, A & rhs)
{
std::swap(lhs.m_name, rhs.m_name);
std::swap(lhs.m_type, rhs.m_type);
}
A & operator=( const A & rhs)
{
A tmp(rhs);
swap(*this, tmp);
return *this;
}
friend ostream & operator<<( ostream & os,A & x)
{
x.print(os);
return os;
}
protected:
virtual void print(ostream & os) =0;
string m_type;
string m_name;
};
class B : A
{
public:
B(string name, int att) :
A(name),
m_att(att)
{
m_type="B";
}
B( const B & rec) :
A(rec),
m_att(rec.m_att) {}
friend void swap(B & lhs, B & rhs)
{
std::swap(lhs.m_att, rhs.m_att);
}
B & operator=( const B & rec)
{
B tmp(rec) ;
swap(*this, tmp);
return *this;
}
private:
virtual void print(ostream & os);
int m_att;
};
Error message:
In member function ‘A& A::operator=(const A&)’:|
error: cannot declare variable ‘tmp’ to be of abstract type ‘A’|
because the following virtual functions are pure within ‘A’:|
virtual void A::print(std::ostream&)|
As your compiler informs you, you cannot create a variable of abstract type. There is no way of dancing around that.
This leaves you three main options:
Stop using pure virtual functions
First, you could just get rid of the pure virtual methods and provide a little stub in each of them that calls std::terminate, which would obviously break compile time detection of whether all (former) pure virtual methods are overridden in all derived classes.
This will cause slicing, since it will only copy the base class and everything that makes out the derived class is lost.
Use a stub class w/o pure virtual functions
Similar to that, you could create a derived class that implements all virtual methods with simple stubs (possibly calling std::terminate), and is used only used as a "instantiatable version of the base class".
The most important part to implement for this class would be a constructor that takes a const reference to the base class, so you can just use it instead of copying the base class. This example also adds a move constructor, because I am a performance fetishist.
This causes the same slicing problem as the first option. This may be your intended result, based on what you are doing.
struct InstantiatableA : public A {
InstantiatableA(A const& rhs) : A(rhs) { }
InstantiatableA(A&& rhs) : A(::std::move(rhs)) { }
void print(ostream&) override { ::std::terminate(); }
};
A& A::operator=(InstantiatableA rhs) {
using ::std::swap;
swap(*this, rhs);
return *this;
}
Note: This is really a variable of type A, although I said it could not be done. The only thing you have to be aware is that the variable of type A lives inside a variable of type InstantiatableA!
Use a copy factory
Finally, you can add a virtual A* copy() = 0; to the base class. Your derived class B will then have to implement it as A* copy() override { return new B(*this); }. The reason dynamic memory is necessary is because your derived types may require arbitrarily more memory than your base class.
You're just facing the fact that inheritance works awkwardly with copy semantics.
For instance, imagine you found a trick to pass the compiling phase, what would mean (following example uses assignment but the issue is the same with a copy) :
// class A
// a class B : public A
// another class C : public A inheriting publicly from A
// another class D : public B inheriting publicly from B
B b1;
C c1;
D d1;
// Which semantic for following valid construction when copy/assignment is defined in A ?
b1 = c1;
b1 = d1;
A &ra = b1;
B b2;
// Which semantic for following valid construction when copy/assignment is defined in A ?
ra = b2;
ra = c1;
ra = d1;
CRTP is a choice:
template<typename swappable>
struct copy_swap_crtp{
auto& operator=(copy_swap_crtp const& rhs){
if (this==std::addressof(tmp))
return *this;
swappable tmp{rhs.self()};
self().swap(tmp);
return *this;
};
auto& operator=(copy_swap_crtp && rhs){
self().swap(rhs.self());
return *this;
};
protected:
auto& self(){return *static_cast<swappable*>(this);};
//auto& self()const{return *static_cast<swappable const*>(this);};
};
user class:
struct copy_swap_class
: copy_swap_crtp<copy_swap_class>
{
copy_swap_class(copy_swap_class const&);
void swap(copy_swap_class&);
};
cheers,
FM.
The compiler is right. The class A is abstract class, therefore you can not create instances of it in the operator=.
In B, you just declared the print function, but you didn't implement it. Meaning, you will get linking errors.
By implementing it, it compiles fine (if we ignore various warnings) :
void B::print(ostream & os )
{
os << m_att;
}
by the way :
B inherits privately from A, is that what you wanted?
order of initialization in A's copy constructor is wrong
you initialized m_type in A's constructor's body and not in the initialization list

Operator overload for derived classes

I have a base container class, which has a number of operators (=,+,-,+=,etc). It is expected that the logic of the operators will not need to be changed for the derived classes. Thus, ideally, I would like to use the base class operators for all of its derived classes without having to redefine them for each of the derived classes explicitly (with the exception of the assignment operator).
A solution that I came up with is demonstrated below based on a simple example. The solution seems to work, but I have doubts about the validity of the method for more complicated cases. Do you think it is valid to use this assignment "hack" in class B? What are the potential pitfalls of this method? Is there anything I missed? Are there easier ways of achieving the functionality that I need (i.e. using base class operators for derived classes)?
class A
{
protected:
int a;
public:
A(int ca)
{
a=ca;
}
A(const A& A1)
{
a=A1.a;
}
int geta() const
{
return a;
}
void seta(int ca)
{
a=ca;
}
const A& operator=(const A& A1)
{
a=A1.a;
return *this;
}
};
const A operator+(const A& A1, const A& A2)
{
A myA(A1.geta()+A2.geta());
return myA;
}
class B: public A
{
public:
B(int a): A(a) {}// ... using A::A;
const B& operator=(const B& B1)
{
a=B1.geta();
return *this;
}
const B& operator=(const A& B1)
{
a=B1.geta();
return *this;
}
};
int main()
{
B myB(4);
A myA(3);
//need this to work
myB=myB+myB;
cout << myB.geta();
myA=myA+myA;
cout << myA.geta();
int j;
cin >> j;
}
For the example given i don't see any problems that can happen. Of cause you can improve the code, first by returning non const reference in operator=, second i think by adding += op to your class, and using it's code inside global operator+ function.
But in general i think it should work fine. As for assignment operators - as soon as you have only POD types and no pointers, or references or handles you don't really need any.
It will become more complicated, however when pointers appear. You'll need to make sure you copy objects, pointed by them, or manage them some other way.
And you probably will not need to modify your operators as long as you don't add more members to derived classes, which also should take part in calculations.
In general you don't have to redefine functions in the base class for derived classes. With public inheritance your derived classes will have access to those functions and use their operation just fine. If you do want to re-define them (= operator for example), be sure you call the right one (virtual functions help in this case).

Operator Overloading for Objects in Multiple Classes

So can you overload operators to handle objects in multiple classes (specifically private members.)
For example if I wanted == to check if a private member in Class A is equal to objects in a vector in Class B.
For example:
bool Book::operator==(const Book& check){
return(((ISBN1 == check.ISBN1) && (ISBN2 == check.ISBN2) && (ISBN3 == check.ISBN3)
&& (ISBN4 == check.ISBN4)) || (title_ == check.title_));}
Everything in that overload is part of the Book class, however what if I wanted to do something like this.
if(*this == bookcheckout[i])
with bookcheckout being part of a Library class. The == would fail in trying to compare title_ to a title_ stored in a vector of the Library class.
It's odd because I have the program doing the exact same thing in two different places, but in one place it's working and in the other it isn't.
Answered: had to have the function that the operator was in be a member function of the same class that the operator was a member function of
If you make operator friend or member of one class, it will be able to access its private members. To access privates of both, operator will have to be free standing friend of both.
That is a bit unwieldy, so consider making public interface for interesting things instead.
(suppressed all puns about accessing private parts of multiple entities)
Here is how you can make a very friendly operator, but again, this is not a good solution.
(didn't compile the code)
class B;
class A
{
friend bool operator==(const A&, const B&);
private:
int private_;
};
class B
{
friend bool operator==(const A&, const B&);
private:
int private_;
};
bool operator==(const A& a, const B& b)
{
return a.private_ == b.private_;
} class B;
This is a better way -- just make public getters and use them in operator.
class A
{
public:
int GetPrivate() const { return private_; }
private:
int private_;
};
class B
{
public:
int GetPrivate() const { return private_; }
private:
int private_;
};
bool operator==(const A& a, const B& b)
{
return a.GetPrivate() == b.GetPrivate();
}
You also can make operator to be part of one of the classes, if you need privates from it alone.
Read up on operator overloading syntax for more.
You don't specify the type of bookcheckout, so I can't be sure, but I think that your operator== will work without change.
For instance, if the code is:
class Library
{
public:
const Book & operator[] (int i);
};
Library bookcheckout;
Then your if statement will call the operator== you have without a problem.
Yes. If you need to access private members, consider providing an appropriate public interface for them OR go for friend class. It is usually better to avoid it though. To handle a specific type, implement operator== with an instance of that type.
You can, but you would need to make either 'bool operator==(A a, B a)' 'friend' of class A if you are using a free function or make class B 'friend' of class A if you implement the comparison operator as a class member function.
You can avoid the friendship requirement by providing a public accessor to the private member in class A