I have a base class and a sub-class that inherits it. I have overridden the operators <, >, <= and >= in the base class, with the purpose of std::sorting a vector with this class. When I std::sort, I do so by calling std::sort(my_vector.begin(), my_vector.end()).
However, I keep getting the error invalid operands to binary expression ('const my_sub_class' and 'const my_sub_class'). I also get like 8 errors and a whole essay of sub-errors for every place I try to implement the sort. For example, I get in instantiation of member function 'std::__1::greater<my_sub_class>::operator()' requested here, if (__comp(*--__last, *__first)), which seems to be the various sub functions.
I hope I've just missed an include, but apart from #include <vector> (d'uh) and #include <algorithm> I can't figure out what else I need. I have tried the overloaded operators separately through if's, and they work. The vector<my_sub_class> works as well. I've also tried various solutions such as overloading the operators in the sub-class, and supplying an explicit sort function (such as greater<my_sub_class>, own functions, reverse sort order via rbegin() and rend()), but nothing seems to work (although some of my solutions give different errors (too varied to include all here).
EDIT:
Here's some code that reproduces the error
Header File:
#ifndef H_DEBUGGING
#define H_DEBUGGING
class my_class {
public:
void set_value(int in_value);
int get_value();
bool operator < (const my_class & in_my_class);
bool operator > (const my_class & in_my_class);
// Some other stuff
protected:
int mValue;
my_class();
// Some other stuff
};
class my_sub_class: public my_class {
public:
my_sub_class();
// Some other stuff
protected:
// Some other stuff
};
void debug_custom_class_vector();
#endif
Class File:
#include <algorithm>
#include <iostream>
#include <vector>
#include "Debugging.hpp"
my_class::my_class() {
}
void my_class::set_value(int in_value) {
mValue = in_value;
}
int my_class::get_value() {
return mValue;
}
bool my_class::operator < (const my_class & in_my_class) {
return mValue < in_my_class.mValue;
}
bool my_class::operator > (const my_class & in_my_class) {
return mValue > in_my_class.mValue;
}
my_sub_class::my_sub_class() {
}
void debug_custom_class_vector() {
my_sub_class sub_a, sub_b, sub_c;
sub_a.set_value(2);
sub_b.set_value(1);
sub_c.set_value(3);
std::vector<my_sub_class> my_custom_vector;
my_custom_vector.push_back(sub_a);
my_custom_vector.push_back(sub_b);
my_custom_vector.push_back(sub_c);
std::cout << "Unsorted: " << std::endl;
for (int i = 0; i < 3; i++) {
std::cout << i << ": " << my_custom_vector[i].get_value() << std::endl;
}
// std::sort(my_custom_vector.begin(), my_custom_vector.end(), std::greater<my_sub_class>());
std::cout << "Sorted: " << std::endl;
for (int i = 0; i < 3; i++) {
std::cout << i << ": " << my_custom_vector[i].get_value() << std::endl;
}
}
// Some other stuff
When I then run from my main, I get:
Unsorted:
0: 2
1: 1
2: 3
Sorted:
0: 2
1: 1
2: 3
and when I uncomment the std::sort line in the class file, I get the error.
What can I do to solve it?
std::sort requires the operators to be const methods. Declaration
virtual bool operator < (classA a);
virtual bool operator < (const classA& a);
virtual bool operator < (classA& a) const;
All three declarations are not suitable for your case, either won't compile or won't work. You need:
virtual bool operator < (const classA& a) const;
Plus, you'll probably need to make copy/move operators virtual...
Also, to begin with, you shouldn't write virtual comparison operator (it cripples performance, possibly 10~100 times for sort). Better use lambda functions for customized sorting. Only in some really weird cases you have to resort to virtual functions. Honestly, I don't know why you need comparison operator to be virtual for sorting... I think you made an error somewhere.
So you'd better check out lambda functions in C++11 and redesign your code.
Related
Sorry for the not clear title.
Recently I started to learn C++ and I don't know how to overload operator << to make it repeatable.
Here's an example code.
class Foo{
private:
int* a;
int idx = 0;
public:
Foo(){a = new int[100];
void operator<< (int a) {arr[idx++] = a;}
What << does is basically class get integer number as an operand and save it into arr.(Ignore overflow case here)
For example, a << 100 will add 100 into array.
What I want to do is make << operator can be repeatedly used inline like a << 100 << 200
How should I fix above code to allow this function?
Thanks in advance :)
The overloaded Foo::operator<<() takes actually two arguments:
The parameter int given as right-hand side
The implicit this from left-hand side.
To allow chaining of this operator, it should return a reference to the left-hand-side (i.e. *this) to become usable at left-hand-side itself.
Sample code:
#include <iostream>
struct Foo {
Foo& operator<<(int a)
{
std::cout << ' ' << a;
return *this;
}
};
int main()
{
Foo foo;
foo << 1 << 2 << 3;
}
Output:
1 2 3
Live demo on coliru
Chaining is enabled by returning a reference to the instance so you can call another method:
class Foo{
private:
std::vector<int> a;
public:
Foo(){}
Foo& operator<< (int a) {
arr.push_back(a);
return *this;
}
};
Now you can call f << 100 << 200 << 42;.
Note that I replaced the array with a std::vector to make Foo less broken (unless you have a descrutor that you did not show it was leaking memory, you could fix that, but then still copying would cause problems, in short you need to respect the rule of 3/5 when you own a resource, using a std::vector makes things much simpler).
PS: Same works for other methods. You simply call another method on the returned reference to this. Note that operators are just methods (with some syntactic sugar) and to see that you can write as well f.operator<<(100).operator<<(200).operator<<(42);.
Return a reference to *this. It's unrelated but you should use a vector to avoid memory leaks. Try to avoid raw new
class Foo{
private:
std::vector<int> a;
public:
Foo &operator<< (int a) {
arr.push_back(a);
return *this;
}
};
Given the following C++ program:
#include "counterType.h"
#include <iostream>
#include <string>
using namespace std;
counterType::counterType()
{
counter = 0;
}
counterType::counterType(int c)
{
setCounter(c);
}
void counterType::setCounter(int ck)
{
counter = ck;
}
int counterType::getCounter()
{
return counter;
}
void counterType::incrementCounter()
{
++counter;
}
void counterType::decrementCounter()
{
--counter;
}
void counterType::print()
{
cout << "Counter = "<< counter << endl;
}
The code seems to only work when setCounter() has an argument in it. The only tests that fail are when is has no argument. So how do I check it in a way that if there is no argument, then the counter would be 0?
This is the perfect place for a default function argument. Since this is a class member function that means you need to change your function declaration to be
void setCounter(int ck = 0);
To tell the compiler that if a value is not provided for ck that it can use 0 as the default value. That means your function definition stays the same since it "pulls in" the default value from he declaration.
Two approaches:
1) Supply a default argument in the function declaration so you can call the function without supplying it.
void setCounter(int ck = 0);
2) Overload the function
void counterType::setCounter()
{
counter = 0;
}
Some software houses (particularly those where the code standard guys are Java folk) disallow the first style. A less facetious reason for not liking the first way is that the default argument value can be run-time evaluable (a member variable perhaps) and that can harm program stability.
For starters you can initialize the data member counter in the declaration of the data member within the class definition. For example
class counterType
{
//...
int counter = 0;
};
In this case the constructors can look like
counterType::counterType()
{
}
counterType::counterType(int c) : counter( c )
{
}
Or you could define the constructors the following way
counterType::counterType() : counterType( 0 )
{
}
counterType::counterType(int c) : counter( c )
{
}
The function setCounter can have a default argument
void counterType::setCounter(int ck = 0 )
{
counter = ck;
}
It is better to declare the function getCounter within the class definition like
int getCounter() const;
because the function does not change the object itself. And define it like
int counterType::getCounter() const
{
return counter;
}
And this function
void counterType::print()
{
cout << "Counter = "<< counter << endl;
}
is better to declare and define like
std::ostream & print( std::ostream &os = std::cout ) const;
and define it like
std::ostream & print( std::ostream &os = std::cout ) const;
{
return os << "Counter = "<< counter << endl;
}
It also does not change the object itself so it should be declared with the qualifier const.
As it seems your class has only one data member then you could define the operator << for the whole class. For example
class counterType
{
//...
friend std::ostream & operator <<( std::ostream &os, const counterType &c );
};
std::ostream & operator <<( std::ostream &os, const counterType &c )
{
return os << "Counter = "<< c.counter << endl;
}
Do you mean something like that?
void counterType::setCounter()
{
counter = 0;
}
What you're trying to achieve is called function overloading: given a different list of arguments, C++ lets you define a different "version" of the same function.
void counterType::setCounter() // No argument in there
{
counter = 0;
}
I am trying to make a polymorphic vector using std::reference_wrapper for these classes:
struct Int2TypeBase{
virtual void which(){ std::cout << "Int2TypeBase" << "\n";}
};
template <int v>
struct Int2Type : public Int2TypeBase
{
enum
{
value = v
};
void which(){ std::cout << "Int2Type<" << value << ">""\n";}
friend bool operator==(const Int2Type& lhs, const Int2Type& rhs){
return lhs.v == rhs.v;
}
};
Now I am trying to make use of std::reference_wrapper like this:
int main(){
using namespace std;
std::vector<std::reference_wrapper<Int2TypeBase>> v;
Int2Type<0> i2t_1;
v.emplace_back(i2t_1);
auto x = v[0];
x.get().which();
std::cout << typeid(x.get()).name() << "\n";
// std::cout << (x.get() == i2t_1) << "\n";
}
The output is:
Int2Type<0>
8Int2TypeILi0EE
This is what I would expect.
Now however, when I uncomment std::cout << (x.get() == i2t_1) << "\n"; I will get
invalid operands to binary expression ('Int2TypeBase' and 'Int2Type<0>')
This confuses me, as typeid(x.get()).name() returned 8Int2TypeILi0EE rather than F12Int2TypeBasevE which is what I get for typeid(Int2TypeBase()).name();. Furthermore which() also was called for the derived class... so then why does x.get() in x.get() == i2t_1 evaluate to a Int2TypeBase?
Your comparison operator is only defined for derived classes, but the reference wrapper produces (static) type Int2Base, so overload resolution does not even find your comparison operator!
What you probably need is a comparison operator of the form
bool operator==(const Int2TypeBase& lhs, const Int2TypeBase& rhs)
but then you also need to have some sort of polymorphic dispatch to perform the actual comparison (presumably assuming that the dynamic types match).
At compile time, the compiler can only tell that the type of x.get() is Int2TypeBase, because as declared you can put any Int2TypeBase there. So at compile time, it can't determine that the == operator will work.
At run time, the objects you put in the collection reference their full type, so typeid returns what you expect and the correct virtual function is called.
I'm trying to understand how to properly overload the "<<" operator so that I can use
std::cout << my_object;
to print useful debug messages. In particular, I need to have an implementation of << for each of my subclasses, so I'm declaring << to be virtual in the superclass.
Right now I'm stuck with the following piece of code
#include <iostream>
using namespace std;
class Shape {
public:
virtual ~Shape() { };
virtual ostream& operator<<(std::ostream &strm) = 0;
};
class Square : public Shape {
int size;
public:
Square() { size = 10; }
~Square() { }
ostream& operator<<(std::ostream &strm) {
return strm << "a square with size " << size;
}
};
int main() {
Square *my_square = new Square();
cout << "my_square is " << my_square << "\n";
}
which (I think) should be working, but doesn't. What I get when using "<<" is that the pointer value of my_square gets printed, rather than the result of the overloaded << .
$ ./a.out
my_square is 0xcacc20
What am I missing here?
operator<< can't be a member function. This is because of the order of the arguments. The stream has to come first.
When calling an overloaded operator, such as:
os << object;
the compiler will attempt to look up both
os.operator<<(object);
and
operator<<(os, object);
(The rules for this can be rather complex, I won't attempt to describe them here.)
Because the stream always comes on the left, your member function will never be found, since it would have to be called as:
object.operator<<(os);
You need to write a free function like:
ostream& operator<<(std::ostream &strm, Square const& square) {
return strm << "a square with size " << square.size();
}
(where Square::size() returns the size member).
Then you need to remember to dereference your pointer too:
std::cout << *my_square << '\n';
Although I see no reason to be dynamically allocating my_square in this example anyway. Just stick it on the stack as a local variable.
If the aim here is ultimately to be able to print any Shape&, and have the printed output follow the "real" type, you would need to create:
virtual std::ostream& print(std::ostream&) const = 0;
in the Shape base class, and override it in each derived class, then have a free function:
std::ostream& operator<<(std::ostream& os, Shape const& shape)
{
return shape.print(os);
}
It is often advised to make all binary operators on your type non-member functions, so that both arguments are treated equally, and the operation remains commutative. See Scott Meyers, Effective C++ (3rd Edition), Item 24, (or find a summary online).
As noted by others, the problem is that operator << can't be member function (because of the order of arguments). The canonical way to do this is to have operator <<(const Shape&) call a virtual function in Shape
class Shape {
friend ostream& operator<<(std::ostream& str, const Shape& shape);
virtual void do_print(ostream& str) = 0;
public:
virtual ~Shape() { };
};
ostream& operator<<(std::ostream& str, const Shape& shape) {
shape.do_print(str);
return str;
}
Note that it is legal to have do_print be private, even though it is going to be (must be) overridden by derived classes. You could make it protected though if you like.
What am I missing here?
You have created operator which will get you class as a first argument and stream as the second.
my_square << std::cout;
I'd create free function and to make it dynamic I'd call some virtual method in it
I'm playing around with composition, and in one of my classes I have a wrapper around the subscript operator "[ ]" (from std::vector). However, the compiler (g++) gets mad when I say this->[i]. I've worked around this issue by using (*this)[i] instead, but I thought these were synonyms. What am I missing? Here is a small sample code that throws the error (I'm purposely avoiding iterators in newmethod just to simply illustrate my problem).
#include <vector>
#include <iostream>
class A {
private:
std::vector<int> rep;
public:
std::size_t size() { return rep.size(); }
int& operator[](std::size_t index) { return rep[index]; }
void newmethod();
A(size_t n, int m) : rep(n,m) {}
};
void A::newmethod() {
for (std::size_t i=0; i < (this->size()); ++i) {
std::cout << (*this)[i] << " ";
}
for (std::size_t i=0; i < (this->size()); ++i) {
std::cout << this->[i]; << " "; //Causes an error!
}
return;
}
int main() {
A(17,3).newmethod();
return 0;
}
You have to call the operator[] member function directly, something like:
this->operator[](i)
a->b is equivalent to (*a).b. What exactly do you expect to happen when you say a->[b] and it translates to (*a).[b]?
That is not correct, if we look at the draft C++ standard we can see that E1->E2 is equivalent to (*(E1)).E2 and not (*E1)E2, this is covered in section 5.2.5 Class member access paragraph 2:
[...]The expression E1->E2 is converted to the equivalent form (*(E1)).E2;[...]
so what follows -> has to be a member of the class(or a base class), so in this case that would be operator[]:
this->operator[](i)