I would like to define an abstract base class X and enforce the following:
a) every concrete class Y that inherits from X define a constructor Y(int x)
b) it should be possible to test whether two Y objects are equal.
For a, one not very good solution is to put a pure virtual fromInt method in X
which concrete class will have to define. But I cannot enforce construction.
For b), I cannot seem to use a pure virtual method in X
bool operator == (const X& other) const =0;
because in overridden classes this remains undefined. It is not enough to define
bool operator == (const Y& other) const { //stuff}
because the types don't match. How do I solve these problems?
You can force construction by making the no argument constructor private and having a public single int argument constructor in your base class. As long as the base class has some pure virtual methods, then your subclasses must call that constructor.
As for the operator==, try defining
bool operator == (const BaseClass& other) const { .. };
in all of your subclasses. Worst case, you can define a public equals(const BaseClass& other) method that is pure virtual in your base.
EDIT: the forcing constructor thing is not entirely true. What I suggested forces sub classes to call the single argument constructor. They could have a no argument constructor that passes a constant up to the base in constructor.
There's an easy solution.
// Class X
// (... some documentation ...)
//
// ** NOTE: All subclasses of X must have a constructor that takes a single int,
// ** and overload operator==.
class X {
...
For b), you can define virtual bool operator == (const X & other) const = 0 in X.
You can't have const Y & other as the parameter in the comparison, but Ys will be automatically casted to Xs and then you can use dynamic_cast to see if it's a class that you can compare with.
a - should be possible if you use CRTP and an intermediary, friend, templated subclass that all user code must inherit from. Something like so:
struct X
{
virtual bool compare(X const&) const = 0;
private:
X();
template < typename T >
friend struct client_base; // don't recall the correct code here.
};
template < typename Sub >
struct client_base : X
{
// use boost::concepts to verify Sub has Sub(int)
Sub() : X() {}
};
struct Y : client_base<Y>
{
Y(int);
bool compare(X const& x)
{
if ((Y* other = dynamic_cast<Y*>(x)) && *other == *this) return true;
return false;
}
};
Obviously I've left a lot for you to figure out to make this a complete solution.
a) doesn't have a sense as for me but you can create something
template< typename T >
Base* create( int x )
{
return T::create( x );
}
for b) ask google about "multi methods" implementation in c++
Enforcing to be constructible from an integer does not make any sense: each derived class is free to define its constructors as it wishes. You can however enforce them to pass an integer to the base class... not that it makes much more sense anyway.
The operator== is also contorted, you can however get the essence of it:
class Base
{
public:
bool operator==(const Base& rhs) const;
bool operator!=(const Base& rhs) const { return !(*this == rhs); }
private:
virtual bool equals(const Base& rhs) const = 0; // will pass only objects
// of the same dynamic type
};
bool Base::operator==(const Base& rhs) const
{
return typeid(*this) == typeid(rhs) && this->equals(rhs);
}
bool Derived::equals(const Base& rhs) const // We KNOW Base is actually a Derived
{
return *this == static_cast<const Derived&>(rhs);
}
You could try and prettify it a bit by using templates and CRTP, but what if Derived was inherited from ? it would not hold.
Related
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;
}
I have a number of structs that are derived from the same base for the purpose of code reuse, but I do not want any form of polymorphism.
struct B {
int field;
void doStuff() {}
bool operator==(const B& b) {
return field == b.field;
}
};
struct D1 : public B {
D1(int field) : B{field} {}
};
struct D2 : public B {
D2(int field) : B{field} {}
};
Structs D1 and D2 (and more similar structs) derive from B to share common fields and methods, so that I would not need to duplicate those fields and methods in each of the derived classes.
Struct B is never instantiated; I only use instances of D1 and D2. Furthermore, D1 and D2 are not supposed to interact with each other at all. Essentially, I do not want any polymorphic behaviour: D1 and D2, for all purposes, should act as unrelated structs.
I would like any D1 to be compared with other D1s for equality, and any D2 to be compared with other D2s for equality. Since D1 and D2 don't contain any fields, it would seem appropriate to define an equality operator in struct B.
However, (as expected) I get the following interaction between D1 and D2:
int main() {
D1 d1a(1);
D1 d1b(1);
D2 d2(1);
assert(d1a == d1b); // good
assert(d1a == d2); // oh no, it compiles!
}
I don't want to be able to compare D1 with D2 objects, because for all purposes, they should act as if they are unrelated.
How can I make the last assertion be a compile error without duplicating code? Defining the equality operator separately for D1 and D2 (and all the other similar structs) would mean code duplication, so I wish to avoid that if possible.
"Structs D1 and D2 (and more similar structs) derive from B to share common fields and methods"
Then make B a private base class. Obviously, D1 and D2 shouldn't share their equality operator, since the two operators take different arguments. You can of course share part of the implementation as bool B::equal(B const&) const, as this won't be accessible to outside users.
You can use CRTP to define operator == only on the reference to the base class of the final type:
template<typename T>
struct B {
int field;
void doStuff() {}
bool operator==(const B<T>& b) {
return field == b.field;
}
};
struct D1 : public B<D1> {
D1(int field) : B{field} {}
};
struct D2 : public B<D2> {
D2(int field) : B{field} {}
};
This causes the first assert to compile and the second one to be rejected.
Instead of defining your equality operator as part of the base class, you usually need two functions in the derived classes:
struct B {
int field;
void doStuff() {}
};
struct D1 : public B {
D1(int field) : B{field} {}
bool operator==(const D1& d) {
return field == d.field;
}
};
struct D2 : public B {
D2(int field) : B{field} {}
bool operator==(const D2& d) {
return field == d.field;
}
};
Or, as is generally preferred, you could make them free functions:
bool operator==(const D1 &lhs, const D1 &rhs)
{
return lhs.field == rhs.field;
}
bool operator==(const D2 &lhs, const D2 &rhs)
{
return lhs.field == rhs.field;
}
Note: If field was not a public member, you would need to declare the free function version as a friend.
Handling a large number of arbitrary types
Okay, so maybe you have D3 through D99, as well, some of which are indirect descendant of B. You'll need to use templates:
template <class T>
bool operator==(const T &lhs, const T &rhs)
{
return lhs.field == rhs.field;
}
Great! But this grabs everything, which is bad for unrelated types that are not supposed to be comparable. So we need constraints.
TL;DR; Solution
Here's a trivial implementation without any code duplication (i.e. works for an arbitrary number of derived types):
template <class T, class = std::enable_if<std::is_base_of<B,T>()
&& !std::is_same<B, std::remove_cv_t<std::remove_reference_t<T>>>()>>
bool operator==(const T &lhs, const T &rhs)
{
return lhs.field == rhs.field;
}
The enable_if checks first that T inherits from B then ensures it's not B. You stated in your question that B is basically an abstract type and is never directly implemented, but it's a compile-time test, so why not be paranoid?
As you later noted in comments, not all D# are derived directly from B. This will still work.
Why you are having this issue
Given the following:
D1 d1(1);
D2 d2(2);
d1 == d2;
The compiler has to find a comparison operator, whether a free function or member of D1 (not D2). Thankfully, you've defined one in class B. The third line above can equivalently be stated:
d1.operator==(d2)
operator==, however, is part of B, so we're basically calling B::operator==(const B &). Why does this work when D2 is not B? A language lawyer would clarify if it's technically argument dependent lookup (ADL) or overload resolution, but the effect is that D2 is silently cast to B as part of the function call, making this equivalent to the above:
d1.operator==(static_cast<B>(d2));
This happens because no better comparison function can be found. Since there's no alternative, the compiler selects B::operator==(const B &) and makes the cast.
You can remove the equality operator from your original definition of the struct and replace it with a function template accepting two identical parameter types:
template <class T> bool operator == (const T& lhs, const T& rhs)
{
return lhs.field == rhs.field;
}
Note that this function is somewhat "greedy", it might be best to put it in a namespace (together with the structs, to enable ADL) or to further constrain the types like this:
#include <type_traits>
template <class T, std::enable_if_t<std::is_base_of_v<B, T>, int> = 0>
bool operator == (const T& lhs, const T& rhs)
{
return lhs.field == rhs.field;
}
(note that std::is_base_of_v requires C++17, but the verbose counterpart exists since C++11).
As a last tweak, in order to prevent such an explicit instantiation:
operator == <B>(d1a, d2); // ultra-weird usage scenario, but compiles!
or (as #Aconcagua pointed out in the comments) type deduction with base-class references to the derived structs,
B& b1 = d1a;
B& b2 = d2;
assert(b1 == b2); // Compiles, but see below.
you also might want to add
template <> bool operator == <B>(const B&, const B&) = delete;
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
I wish to create an interface for a class C which has this function:
friend bool operator==(const C& a, const C& b);*
I wish to the create a mock for C for test driven purposes.
I tried doing it like this:
class IC
{
virtual friend bool operator==(const IC& a, const IC& b) = 0;
};
What should I do?
operator == is a binary operator. To make it virtual, it must be a class member.
class IC
{
virtual bool operator==(const IC& b) = 0;
};
In this case, the first argument to == is implicitly this.
Your declaration is about a free function, not a class member.
EDIT: As suggested in the comments, you should avoid this and rather implement a compare function or similar.
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