I am writing a class and I got to the point where I can do operations that mix my class type objects and C++ literals, but in one direction only.
here is a simplified code that shows the idea:
#include <iostream>
#include <string>
using namespace std;
class CLS
{
string str;
public:
CLS(const char* param)
{ str = param; }
CLS operator+(const CLS& rhs)
{
str = str + rhs.str;
return *this; }
friend ostream& operator<<(ostream& out, const CLS& rhs);
};
ostream& operator<<(ostream& out, const CLS& rhs)
{
out << rhs.str;
return out; }
int main()
{
CLS a("\n Hello ");
CLS b("bye!\n\n");
cout << a + "World!\n\n";
//cout << "\n Good " + b; /* this is not possible because of the operands order */
}
As you see, I can do something like:
a + "W";
but not,
"W" + a;
As indicated in the last line of the code.
I understand the reason.
The first is equivalent to:
a.operator+("W");
which is covered by my class. However, the second is like,
"W".operator(a);
which is not covered and the literal itself is not an object of a class as I understand. And so, the expression as whole cannot be.
I understand I can create a user defined literals, but this is not what I want to do here. (although I am not sure if they gonna work or not).
I could not find any hint browsing questions I supposed to be related on this site, and I could not get something related to my issue on the net.
My question:
Is there a way that can make either order works?
This code:
cout << "\n Good " + b; /* this is not possible because of the operands order */
does not work because you made operator+ member (and not const member). If you rewrite it as standalone function (probably friend) then this problem would go away:
friend
CLS operator+(const CLS& lhs, const CLS& rhs)
{
CLS r;
r.str = lhs.str + rhs.str;
return r;
}
if you create additional ctor that accepts const std::string & it would be even simpler:
friend
CLS operator+(const CLS& lhs, const CLS& rhs)
{
return CLS( lhs.str + rhs.str );
}
note, you should rewrite existing constructor this way:
CLS(const char* param) : str( param )
{}
it is cleaner and more efficient way
You can add a global function:
inline CLS operator+(const char *lhs, const CLS& rhs)
{
return CLS(lhs) + rhs;
}
Related
hello i have problem in my school c++ lab, my bool operator > should be return true if lhs is greater than rhs, however it always return false. i try print out lhs.tostring(), it show the number correctly.
my lhs and rhs is a string value.
due to some confidence restrict from my school work, i am not allow to post all the function of my work.
Updated information: ithis lab only can use c++14 and can't include any additional lib. The int value is written in string, and need to compare which is bigger. Assuming there is no negative and any letter other than number
some part of my header file
#include <cstring>
#include <iostream>
namespace CS170
{
class BigNum
{
public:
/* Constructor of BigNum object.
Takes in a character string and
constructs a BigNum */
BigNum(const char * rhs = "0");
/* one of rule of 3 need destructor */
~BigNum();
/* Return a character pointer pointing
to the start of the array representing the big num */
const char * toString() const;
/* Return how many digits the number has */
size_t getNumDigits() const;
BigNum & operator =(const BigNum & rhs);
private:
size_t len;
char* num;
};
}
bool operator >(const CS170::BigNum &lhs, const CS170::BigNum &rhs);
cpp
namespace CS170
{
BigNum::BigNum(const char * rhs )
:len{strlen(rhs)}, num{new char[len+1]}
{
strcpy(num,rhs);
}
BigNum::~BigNum()
{
}
const char * BigNum::toString() const
{
return num;
}
size_t BigNum::getNumDigits() const
{
return len;
}
}
bool operator >(const CS170::BigNum &lhs, const CS170::BigNum &rhs)
{
CS170::BigNum left_value{lhs};
CS170::BigNum right_value{rhs};
std::cout << std::endl;
std::cout << left_value.toString() << " " << right_value.toString() <<
std::endl;
/*this don't work for comparing**/
if(left_value.toString() > right_value.toString())
return true;
else
return false;
}
left_value.toString() > right_value.toString()
This does not do what you think it does. toString() returns a const char*, a pointer to some data. Formally the behaviour of > in your case is undefined since the pointers are not part of the same array, and even if they were, the result would not depend on the string contents.
To check the lexicogrammatical order of strings, you should use the right tool for it, for instance std::string::operator>:
std::string lhs_string{left_value.toString()};
std::string rhs_string{rght_value.toString()};
if (lhs_string > rhs_string)
// ...
// note: here you could simply do return lhs_string > rhs_string;
If you're using a recent compiler and C++17 is an option, you could also use those tools without copying data around:
#include <string_view>
const char* lhs = "programming";
const char* rhs = "language";
std::string_view lhs_string{lhs};
std::string_view rhs_string{rhs};
lhs_string>rhs_string // lexicogrammatical order
live demo
const char* cannot be compared in the way you are trying to. You have to use strcmp. Example usage would look like:
if (strcmp(left_value.toString(), right_value.toString()) > 0)
{
return true;
}
The last part of the function could even be simplified to:
return strcmp(left_value.toString(), right_value.toString()) > 0;
is nearly there but i don't work if compare 11 > 2, as is still read only the first string.
bool operator >(const CS170::BigNum &lhs, const CS170::BigNum &rhs)
{
CS170::BigNum left_data{lhs};
CS170::BigNum right_data{rhs};
int result = strncmp(left_data.toString(), right_data.toString(),20);
return result > 0;
}
as you can see from the code I want to overload the < operator twice. 1 to sort by dist and the other by nodeID. I would like to check if there is any way to call the different overloaded methods. For example in the compLoc method, when I use the sort() method I want it to be sorted by nodeID but in other methods I want it to be sorted by dist.
struct AttSet{
int nodeID;
double dist;
bool operator < (const AttSet & str) const{
return (dist < str.dist);
}
/*
bool operator <(const AttSet & str){
return (nodeID < str.nodeID);
*/
bool operator == (const AttSet & str){
return nodeID == str.nodeID;
}};
void compLoc(Edge *edge, vector<Node*> &vertices){
int l = edge->length;
int vl = edge->head->nodeID;
int vr = edge->tail->nodeID;
/*
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end());
sort(vertices[vr]->attSet.begin(), vertices[vr]->attSet.end());
vector<AttSet> vInterSec;
set_intersection(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), vertices[vr]->attSet.begin(), vertices[vr]->attSet.end(), back_inserter(vInterSec));
*/}
You cannot have overloads that have the same signature. This holds for any function. How would you try to decide which version to use?
If you want sort the object based on different criteria you should use the sort version that takes a custom comparer function as the third argument.
Edit:
Of course you need to provide the comparer. I would suggest providing the comparers as static functions of the class if you have such power. This way you will not pollute enclosing namespace and you can access privates of the class with out exposing any getters. Since your properties are public the lambda would suffice, and probably be the best/cleanest approach.
Feeling adventurous I made a simple c++11 exercise program. For what it's worth, if you ever decided to go for proper encapsulation, I've shown both approaches:
#include <iostream>
#include <algorithm>
#include <vector>
#include <initializer_list>
#include <cassert>
using namespace std;
template<typename T>
std::ostream& operator<<(std::ostream& out, const std::vector<T>& v){
for(const auto& el : v){
out << el << '\n';
}
return out;
}
class A {
int a;
int b;
public:
A(std::initializer_list<int> l){
assert(l.size() == 2);
auto i = l.begin();
a = *i;
++i;
b = *i;
}
friend std::ostream& operator<<(std::ostream& stream, const A& e){
return stream << e.a << ' ' << e.b;
}
static bool compareViaA(const A& lhs, const A& rhs){
return rhs.a > lhs.a;
}
static bool compareViaB(const A& lhs, const A& rhs){
return rhs.b > lhs.b;
}
};
int main() {
std::vector<A> v {{2,3}, {3,2}, {1,4}, {4,1}};
//sort(v.begin(), v.end(), [](const A& a, const A& b){return a.a > b.a;}) // fails because of privacy violation
sort(v.begin(), v.end(), A::compareViaA);
std::cout << v << '\n';
sort(v.begin(), v.end(), A::compareViaB);
std::cout << v << '\n';
return 0;
}
Live: http://ideone.com/lDMujx.
I think you can implement this by using functor and take the comparator(operator< overload) outside the AttSet.
Here is a simple example:
struct AtrComparator {
bool distcmp;
AttrComparator(bool distcmp): distcmp(distcmp) {}
bool operator() (const AttSet &s1, const AttSet &s2) {
if(distcmp) {
return s1.dist < s2.dist;
} else {
return s1.nodeID < s2.nodeID;
}
}
}
And then you can do the sort through different feed, dist or nodeID.
.e.g:
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), AttComparator(true));
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), AttComparator(false));
You can't do that. They have the same signature exactly.
Use a functor or a lambda and pass it to whatever algorithm you want.
std::sort(std::begin(container), std::end(container),
[](const element_type& lhs, const element_type& rhs) { return ...; });
Another way to do this:
struct compare_by_node_id {
bool operator()(const AttSet& lhs, const AttSet& rhs) const {
return lhs.nodeID < rhs.nodeID;
}
};
struct compare_by_dist {
bool operator()(const AttSet& lhs, const AttSet& rhs) const {
return lhs.dist < rhs.dist;
}
};
And you could pass that to the algorithm like:
std::sort(std::begin(container), std::end(container), compare_by_node_id());
you cannot do that because compiler doesn't see difference between:
bool operator < (const AttSet & str) const; //this const doesn't allow to override any property of object(instance of AttSet) if I remember
and
bool operator < (const AttSet & str);
there're the same same return type, same parameter (same signature)
compiler cannot choose which one is better
There's not a great way to do this as far as I am aware, since the compiler will see these as the exact same and will throw an error. If you need to do this, use the < operator as whatever will occur the most often, and then write a method that you can call to compare two object. Something like this:
bool operator< (const Blah &blah) const {
return (most often operation)
}
bool Blah::other_operation(const Blah &blah) const {
return (other operation)
}
I have written out my class with overloaded operators but I am trying to reduce the amount of memory allocations (as shown by valgrind on Linux). I understand that in certain instances that the copy constructor is called to make a local copy of an object for the function but I'm unsure which situations. As it stands I'm making a new object in each case so I feel that I could get away with ridding some of the "new" calls if I were to make use of the already copied pieces. Below are my operator+ and operator+= for reference.
// ---------------------------------------------------------------------------
// operator+
// Adds two Poly objects
Poly Poly::operator+(const Poly& rhs) const {
//case where rhs has more terms
if (maxExponent < rhs.maxExponent) {
Poly temp(rhs);
for (int i = 0; i <= maxExponent; i++) {
temp.polynomial[i] += polynomial[i];
}
return temp;
}
else {
Poly temp(*this);
for (int i = 0; i <= rhs.maxExponent; i++) {
temp.polynomial[i] += rhs.polynomial[i];
}
return temp;
}
}
// ---------------------------------------------------------------------------
// operator+=
// Adds and assigns two Poly objects
Poly& Poly::operator+=(const Poly& rhs) {
*this = *this + rhs;
return *this;
}
Here is my operator= in case the tricks depend on this:
// ---------------------------------------------------------------------------
// operator=
// Assigns a Poly object to another
const Poly& Poly::operator=(const Poly& other) {
if (&other != this) {
delete[] polynomial;
maxExponent = other.maxExponent;
polynomial = new int[maxExponent + 1];
for (int i = 0; i <= maxExponent; i++) {
polynomial[i] = other.polynomial[i];
}
}
return *this;
}
The technique you are looking for is called "expression templates".
Your operator+ takes two Poly& objects, and returns a should_be_added< Poly&, Poly& >. If you add again, it returns a should_be_added< should_be_added<Poly&, Poly&>, Poly& > (or possibly should_be_added< Poly&, Poly&, Poly& > if you know things commute and you prefer things to be flat, but that is extra work).
should_be_added then has a conversion-to-Poly, or Poly has an implicit should_be_added< T, U >&& constructor (with efficient move these two are equivalent). At that point, you have at compile time the complete tree of expressions you are assigning to your Poly. With lots of work and care, you can efficiently build a single output value.
A good way to start is to start with your operator+=(Poly const& o) and operator+=(Poly&& o) and similar "mutating" operators. These primitives can make writing other operators efficiently much easier.
You probably want to write a custom Poly& operator=( should_be_added<T,U>&& src ) so that it reuses any memory in the existing Poly object. An easy way to do this is to have a method in should_be_added that says Poly result( Poly&& src ), and implement operator Poly() as operator Poly() const { return result( Poly{} ); }, and the operator= is { swap( *this, src.result(std::move(*this)) ); return *this }
Now, none of this is easy -- expression templates are medium-deep template-fu. But the result can be that you can do your mathematical expressions in a natural way, and lose next to nothing.
Note that efficient move semantics should be easy for your Poly class -- just move the internal buffer and clear the source one.
My solution would be to reimplement Poly class with following idea: let's make it impossible to modify field 'polynomials' and make it shared across copies of same Poly using shared_ptr. This way we can have O(1) copy operator while operator+ is still O(n) - with possibility of O(1) in optimistic case :)
Let's also use std::vector instead of table and be careful about our public interface. In return we get:
smaller memory consumption
no code duplication
no need to implement copy constructor; default will work just fine :)
Forgive my sloppy implementation of operator<<. I left out implementation of optimistic case for operator+ as an exercise to the reader :).
Implemented using c++11, because I am not a masochist.
#include <memory>
#include <vector>
#include <initializer_list>
#include <iostream>
class Poly {
public:
Poly() : polynomial_(NULL) {}
Poly(std::initializer_list<double> il)
{
polynomial_.reset(new std::vector<double>(il.begin(), il.end()));
}
unsigned max_exp() const
{
return polynomial_ ? polynomial_->size() : 0;
}
Poly operator+(const Poly& o) const
{
const bool has_bigger_exp = max_exp() > o.max_exp();
const Poly & poly_big = has_bigger_exp ? *this : o;
const Poly & poly_small = has_bigger_exp ? o : *this;
auto * tmp = new std::vector<double>(*poly_big.polynomial_);
for (unsigned i = 0; i < poly_small.max_exp(); ++i) {
tmp->at(i) += poly_small.polynomial_->at(i);
}
Poly ret_obj;
ret_obj.polynomial_.reset(tmp);
return ret_obj;
}
Poly& operator+=(const Poly& o)
{
*this = *this + o;
return *this;
}
private:
std::shared_ptr<const std::vector<double>> polynomial_;
friend std::ostream& operator<<(std::ostream& os, const Poly& obj);
};
std::ostream& operator<<(std::ostream& os, const Poly& obj)
{
if (obj.max_exp() == 0) {
os << "0" << std::endl;
return os;
}
for (unsigned i = obj.max_exp()-1; i > 0; --i) {
double param = obj.polynomial_->at(i);
if (param != 0) {
os << param << " * x^" << i << " + ";
}
}
os << obj.polynomial_->at(0) << std::endl;
return os;
}
int main() {
Poly a = {1, 2, 3};
Poly b = {4, 5};
Poly c = a + b;
Poly d;
std::cout << a << b << c << d;
a += {1, 1};
std::cout << a;
return 0;
}
In the first case, with operator+, conceptually there's not much you can do. You'll need the temporary variable and you'll have to return it by value.
In the second case instead you implementing operator+= using operator+ and therefore making a copy which is then copied within the object itself with operator=. This is extremely inefficient.
For the above reasons, often, people prefer to implement operator+= first, and then implement operator+ as:
Poly Poly::operator+(const Poly& rhs) {
return Poly(*this) += rhs;
}
Which is the opposite of what you are doing here.
Whats wrong with my code shown below? please somebody throw some light. Thanks for your time !
#include<iostream.h>
using namespace std;
struct mydata{
int mx;
mydata(int x = 0){}
mydata operator+(const mydata& rhs){
mydata temp(rhs);
return temp;
}
operator int() const{ return mx; }
operator double() const{ return mx; }
};
int main(){
mydata d;
mydata r = d + 5; // L1
5 + d; // L2
d + d; // L3
}
First, you haven't stated what the problem is, but presumably you want an operator+ that sums the mx values of two mydata objects:
mydata operator+(const mydata& rhs){
return mydata (mx + rhs.mx);
}
Next, I would suggest making this a non-member function, so that the LHS and RHS get treated in the same way, fixing the problem in L2:
mydata operator+(const mydata& lhs, const mydata& rhs){
return mydata (lhs.mx + rhs.mx);
}
Finally, you will have an ambiguous overload remaining, because the compiler cannot decide whether to use the built-in operator+(int,int) or your own operator+(const mydata&, const mydata&). You can fix this by removing the cast operators int() and double().
See demo here.
The problem (stated the comment) is that compiler doesn't know which + you want to execute:
(double)d + 5
or
(int)d + 5
In order to resolve this ambiguoity, you should point the type conversion, or replace one of these operators by a named function:
operator int() const{ return mx; }
operator double() const{ return mx; }
If you want instead use d + mydata(5) you should write so, because the above variants are more likely to be applied
You could provide a few non-member operator+ to enable operator+ with different data type:
mydata operator+(const mydata& lhs, const mydata& rhs){
return mydata (lhs.mx + rhs.mx);
}
mydata operator+(int mx, const mydata& rhs){
return mydata (rhs.mx+mx);
}
mydata operator+(const mydata& lhs, int mx){
return mydata(lhs.mx+mx);
}
You can't do 5 + d. 5 can not be converted to class object like this. For this you need to get the operator + definition out of the class method. (in my knowledge preferably friend).
I'm trying to add two object that they are in the same class.
In the private section of the class I have two int variables
class One {
private:
int num1, num2;
public:
One operator+=(const One&); // - a member operator that adds another One object - to the current object and returns a copy of the current object
friend bool operator==(const One&, const One&); // - a friend operator that compares two One class objects for equality
};
One operator+(const One&, const One&);// - a non-friend helper operator that adds One objects without changing their values and returns a copy of the resulting One
I'm not sure I have a problem on the opeartor+ I guess
One operator+(const One &a, const One &b){
One c,d,r;
c = a;
d = b;
r += b;
r += a;
return r;
}
I think the above code is wrong, but I tried to use like b.num1 and I get compile error
error: 'int One::num1' is private
error: within this context
and I can't use b->num1 as well because the above function is not in the member function section.
error: base operand of '->' has non-pointer type 'const One'
This is how it calls in main
Result = LeftObject + RightObject;
If you have already implemented this member function:
One One::operator+=(const One&);
Then you may implement the non-member addition operator thus:
One operator+(const One& lhs, const One& rhs) {
One result = lhs;
result += rhs;
return result;
}
This can be simplified somewhat into the following:
One operator+(One lhs, const One& rhs) {
return lhs += rhs;
}
This pattern (which you can adapt for all operator/operator-assignment pairs) declares the operator-assignment version as a member -- it can access the private members. It declares the operator version as a non-friend non-member -- this allows type promotion on either side of the operator.
Aside: The += method should return a reference to *this, not a copy. So its declaration should be: One& operator+(const One&).
EDIT: A working sample program follows.
#include <iostream>
class One {
private:
int num1, num2;
public:
One(int num1, int num2) : num1(num1), num2(num2) {}
One& operator += (const One&);
friend bool operator==(const One&, const One&);
friend std::ostream& operator<<(std::ostream&, const One&);
};
std::ostream&
operator<<(std::ostream& os, const One& rhs) {
return os << "(" << rhs.num1 << "#" << rhs.num2 << ")";
}
One& One::operator+=(const One& rhs) {
num1 += rhs.num1;
num2 += rhs.num2;
return *this;
}
One operator+(One lhs, const One &rhs)
{
return lhs+=rhs;
}
int main () {
One x(1,2), z(3,4);
std::cout << x << " + " << z << " => " << (x+z) << "\n";
}
I can't see why the operator+ is wrong:
#include <stdio.h>
class One {
public:
One(int n1, int n2): num1(n1),num2(n2) {}
private:
int num1, num2;
public:
One operator+=(const One& o) {
num1 += o.num1;
num2 += o.num2;
return *this;
}
friend bool operator==(const One&, const One&); // - a friend operator that compares two One class objects for equality
void print() {
printf("%d,%d\n", num1, num2);
}
};
One operator+(const One& a, const One& b) {
One r(0,0);
r += b;
r += a;
return r;
}
int main() {
One a(1,2),b(3,4);
One r = a + b;
r.print();
}