Need help overloading Polynomial class operators C++ - c++

Ive been asked to overload this operator: p[d], to do two things,
Return the coefficiant of the polynomial where the degree is d so just p[d].
Change the coefficiant of the polyinomial where the degree is d so p[d]=c.
Im using linked list to make the polynomials.
This is th first one:
double Polynomial::operator[](const int num)
{
Monomial *ptr = NULL;
ptr = this->First;
while (ptr != NULL)
{
if (ptr->get_deg() == num)
{
return ptr->get_C();
}
ptr = ptr->GetNext();
}
return 0;
}
For the second one I was thinking of returning the adress of the monomial with the same degree and change its coefficiant but it doesnt work since both my functions need to get the same paramter( int degree).
This is my second function:
Monomial& Polynomial::operator[](const int num)
{
Monomial *ptr = NULL;
ptr = this->First;
while (ptr != NULL)
{
if (ptr->get_deg() == num)
{
return (*ptr);
}
ptr = ptr->GetNext();
}
return;
}
This is how its tested even though the second part isnt shown here:
cout << "p[0]=" << p[0] << ", p[1]=" << p[1] << ", p[2]=" << p[2] << ", p[4]=" << p[4] << endl;

You don't need two overloads here. Just change the return type of the first to double &.
p[d]=c;
will change the referenced value (the one stored in ptr) to c. This only works, when get_C() also returns a reference of course (Thanks to Holt for mentioning).
Another point, that might be worth mentionig are const instances, because you can't modify the values of const instances. So a one pattern for getters is the following:
class A {
private:
double d;
public:
// Overload for const instances, can't modify 'd' via the rturn value
const double &getD() const { return d; } const;
// for non-const instances
double &get() { return d; }
};
So for const instances (e.g. const A a)
a.getD() = 3;
won't compile, can't modify a const reference. For non-const instances of A this works and would change the actual value of the member d.
double d = a.getD();
will work for both and just copy the value to local variable.

The "canonical" implementation for operator[] can be seen on cppreference.com:
struct T
{
value_t& operator[](std::size_t idx) { return mVector[idx]; }
const value_t& operator[](std::size_t idx) const { return mVector[idx]; }
};
As you can see, the second overload is const-qualified. You cannot call the first overload on non-const object:
const T t;
t[0] = 1; // Error: t is not const, so the second overload is chosen, and you get
// a const value_type& you cannot assign to.
Depending on your implementation, it can make sense to return different type for the read and write overloads, so a correct version would be:
// Create a separate function to avoid duplicated code:
Monomial* Polynomial::get_monomial_or_throw(const int num) {
Monomial *ptr = this->First;
while (ptr != nullptr) {
if (ptr->get_deg() == num) {
return ptr;
}
ptr = ptr->GetNext();
}
throw std::out_of_range("");
}
// const-qualified version for read-only access:
double Polynomial::operator[](const int num) const {
return get_monomial_or_throw(num)->get_C();
}
// Not const-qualified version for write access:
Monomial& Polynomial::operator[](const int num) {
return *get_monomial_or_throw(num);
}

Related

C++ return another class object

Yes I know it sounds weird, but I'm looking for a way to overwrite the indirection operator to return another class object. Let me explain better:
In main.cpp I got
MyInt *V = new MyInt[10];
(*V)[3]=10;
but I would like to have it like:
MyInt *V = new MyInt[10];
V[3]=10;
In MyInt.h I've used a wrapper to catch and remove the square brackets of MyInt class and then overload the "=" operator. That's because I need a class that could store the vector and also a counter of its usage inside it. More details here.
MyInt.h
wrapper operator[] ( std::size_t i ) { return wrapper( *this, i ) ; }
The work flow is "MyInt::wrapper::operator=".
Now it works but I would like to get rid of (*V). Would be possible to remove it by overloading the indirection operator to return a wrapper object that could be passed to "wrapper::operator=" then?
I was thinking something like:
MyInt& operator*(){
return wrapper(*this)
}
but it doesn't work, I get "error: invalid initialization of non-const reference of type ‘MyInt&’ from an rvalue of type ‘test::wrapper’". I know that the indirection operator should return the same class, but I really need it that way. Any suggestion? Thanks in advance.
Note: This answer was written when OPs question was:
I would like to have it like:
MyInt V = new MyInt[10];
V[3]=10;
I'll leave this answer up in case anyone is interested in a solution for that.
#include <cstddef>
class MyInt {
public:
MyInt() = default;
MyInt(MyInt* d) : data(d) {} // constructor taking a `MyInt*`
// ... rule of 5 implementation needed here ...
MyInt& operator[](size_t idx) { return data[idx]; }
MyInt& operator=(int) { return *this; }
private:
MyInt* data = nullptr;
};
int main() {
MyInt V = new MyInt[10];
V[3]=10;
}
Note that there's no way for V to know how many elements data is pointing at.
Following the link to your earlier question, and the requirements you've added there, V[3] is undefined behaviour.
You have changed the meaning of new [] to return a pointer to a single object.
You need to completely rethink your design, such that there are 10 MyInt objects for V to point to.
struct MyCounts
{
int num_read = 0;
int num_write = 0;
};
class MyInt
{
int value;
MyCounts * counts;
static void* operator new[](size_t n){
void * ptr = malloc(sizeof(MyCounts) + n * sizeof(MyInt));
MyCounts * counts = new (ptr) MyCounts;
ptr = static_cast<void *>(counts + 1);
for (size_t i = 0; i < n; ++i, ptr += sizeof(MyInt)) {
new (ptr) MyInt{ counts };
}
return static_cast<void *>(counts + 1);
}
static void* operator delete[](void* ptr, size_t n){
for (MyInt * last = reinterpret_cast<MyInt *>(ptr) + n; --last != ptr; ) {
last->~MyInt();
}
ptr -= sizeof(MyCounts);
reinterpret_cast<MyCounts *>(ptr)->~MyCounts();
free(ptr);
}
public:
MyInt& operator=(int i) { value = i; ++counts->num_write; return *this; }
operator int() const { ++counts->num_read; return value; }
};
I would like to have it like:
MyInt* V = new MyInt[10];
V[3]=10;
You need MyInt to implement an operator= taking an int to "write" to it, and a conversion oeprator to "read" from it:
#include <iostream>
struct MyInt
{
int value;
MyInt& operator=(int v) { value = v; return *this; }
operator int() const { return value; };
};
int main()
{
MyInt *V = new MyInt[10];
V[3]=10;
std::cout << V[3] << '\n';
}

Assigning object after operation via operator

I want to add contents of two classes and save them in another class. I have created constructor, parameterized constructor, destructor and overloaded = parameter. It is working fine for Demo b = a; but when I try to save the object given by a.addition(b), there's error no viable overloaded '='. My concept is why the object is not getting copied to newly created object?
Class Demo
class Demo
{
int* ptr;
public:
Demo(int data = 0) {
this->ptr = new int(data);
}
~Demo(void) {
delete this->ptr;
}
// Copy controctor
Demo(Demo &x) {
ptr = new int;
*ptr = *(x.ptr);
}
void setData(int data) {
*(this->ptr) = data;
}
int getData() {
return *(this->ptr);
}
Demo operator = (Demo& obj) {
Demo result;
obj.setData(this->getData());
return result;
}
Demo addition(Demo& d) {
Demo result;
cout << "result: " << &result << endl;
int a = this->getData() + d.getData();
result.setData(a);
return result;
}
};
Main
int main(void)
{
Demo a(10);
Demo b = a;
Demo c;
c = a.addition(b); // error here
return 0;
}
The operator= takes a referecne to non-const (i.e. Demo&) as its parameter, which can't bind to the temporary object returned by addition.
To solve the issue you should change the parameter type to reference to const (i.e. const Demo&), which could bind to temporary and is conventional.
BTW: The target and source of the assignment seem to be opposite. I suppose it should be implemented as
Demo& operator= (const Demo& obj) {
setData(obj.getData());
return *this;
}
And declare getData as a const member function.

Dereferencing not working for smart pointer in set

#include<iostream>
#include<set>
template <typename T>
/* Simple smart pointer class */
class SmartPtr
{
T *ptr;
public:
explicit SmartPtr(T *p = NULL) { ptr = p; }
~SmartPtr() { delete(ptr); }
T & operator * () { return *ptr; }
T * operator -> () { return ptr; }
};
class simple {
private:
int x;
public:
simple(int y = 0) :x(y) {}
int getX() { return x; }
};
typedef SmartPtr<simple> simplePtr;
int main() {
std::set<simplePtr> st;
simplePtr p1 = simplePtr(new simple(5));
simplePtr p2 = simplePtr(new simple(5));
simplePtr p3 = simplePtr(new simple(5));
simplePtr p4 = simplePtr(new simple(5));
std::cout << p1->getX(); <-- working fine
st.insert(p1);
st.insert(p2);
st.insert(p3);
st.insert(p4);
for (std::set<simplePtr>::iterator it = st.begin(); it != st.end(); ++it)
{
std::cout << it->getX(); // Not working??
}
}
Compilation is failed with error in Visual Studio 2013:
Error C2039 getX: is not a member of SmartPtr<simple>
On linux:
error: ‘const class SmartPtr<simple>’ has no member named ‘getX’
Is this a problem with iterator??
You can think of it->getX() as a syntactic sugar for (*it).getX(). [In principle, a class can overload the -> and * (dereferencing) operators inconsistently, but std::set<T>::iterator, unsurprisingly, doesn't break that convention]. So, in your case, *it is dereferenced to an lvalue of type const SmartPtr<simple>&, and the .getX() applied to it fails, because SmartPtr doesn't have a getX() method. Since, instead you mean to access the object that the obtained SmartPtr points to, you must add one more level of dereferencing:
Correction 1
Replace it->getX() with (**it).getX() or (*it)->getX().
There is still another problem, though - *it results in a const SmartPtr (yes, std::set's non-constant iterator doesn't provide write access to the container's elements, otherwise you could break correct ordering of elements in the container). But both -> and * (dereferencing) operators in SmartPtr are defined in such a way that they can be invoked only on non-const objects. To fix that, you must make those two functions const:
Correction 2 (in SmartPtr<T>)
// vvvvv
T & operator * () const { return *ptr; }
T * operator -> () const { return ptr; }
// ^^^^^
After you make this second correction, you can replace your old-style for-loop with a range-for loop:
for (const simplePtr& p : st)
{
std::cout << p->getX();
}
Still, your program will not compile - SmartPtr<T> objects cannot be put in an std::set since they are not comparable. Fix that by defining operator<():
Correction 3
Add to SmartPtr<T>:
bool operator<(const SmartPtr& other) const { return ptr < other.ptr; }
At this point your code will compile but chances are high that it will not work correctly. The reason is that the copy-semantics of SmartPtr<T> is left to compiler's discretion which fails to meet your intent. This is easy to guess by spotting the violation of the Rule of Three, Four and Five - your class defines the destructor but fails to define the copy and/or move constructor and the assignment operator. As a result your code performs double deletion and therefore cannot be guaranteed any well defined behavior.
Correction 4
Fix the copy semantics of SmartPtr<T>.
I "fixed" your code by assigning move semantics to SmartPtr (this required adding std::move() when insert()-ing it into std::set):
#include<iostream>
#include<set>
template <typename T>
class SmartPtr
{
T *ptr;
public:
explicit SmartPtr(T *p = NULL) { ptr = p; }
~SmartPtr() { delete(ptr); }
SmartPtr(const SmartPtr& other) = delete;
SmartPtr(SmartPtr&& other) : ptr(other.ptr) { other.ptr = NULL; }
SmartPtr& operator=(SmartPtr other)
{
std::swap(ptr, other.ptr);
return *this;
}
T & operator * () const { return *ptr; }
T * operator -> () const { return ptr; }
bool operator<(const SmartPtr& other) const { return ptr < other.ptr; }
};
class simple {
int x;
public:
simple(int y = 0) : x(y) {}
int getX() { return x; }
};
typedef SmartPtr<simple> simplePtr;
int main() {
std::set<simplePtr> st;
simplePtr p1 = simplePtr(new simple(5));
simplePtr p2 = simplePtr(new simple(5));
st.insert(std::move(p1));
st.insert(std::move(p2));
for (const simplePtr& p : st)
{
std::cout << p->getX();
}
return 0;
}
Your iterator needs to be dereferenced, at which point you get a pointer. Which then needs to be dereferenced. So:
std::cout << (*it)->getX();
For starters you have to define operator < for the class SmartPtr before using it in the set.
Secondly you have to declare the member function getX like
int getX() const { return x; }
And you have to write at least like
std::cout << ( *it )->getX();

Determine lvalue and rvalue in C++ function

UPDATE: I revised some place, and now the problem has changed in some way.
I'm writing a C++ class. Like:
class qqq{
map<int,int> core;
//......
int& operator[](int n){return core[n];};
};
int main(){
qqq a;
a[3]=7;a[5]=0;//Case a
int b=a[3];//Case b
return 0;
}
Although case A and case B are calling the same function(overloaded operator), but case a is used as an lvalue while case b is used as a rvalue.
For some reason, I want to have the effect that if 0 is passed to a[5], delete the node 5 in core. Like:
int& operator[](int n){
if(CASE A && THE VALUE PASSED TO IT IS 0)
core.erase(core.find(n));
else
return core[n];
}
Maybe my description is not accurate.
Here is an implementation of the proxy pattern mentioned in the comments.
Personally, I don't use this, my maps are wrapped in classes that don't provide operator[] at all, instead there are functions like .get(key, default) .init(key), .setdefault(key, default), etc. depending on the class.
// This code is C++11 but it's not essential to the problem.
// The current code calls copy constructors more than necessary.
#include <map>
#include <cassert>
template<class K, class V>
struct zero_map
{
struct proxy
{
std::map<K, V> *container;
K key;
operator V()
{
auto it = container->find(key);
if (it == container->end())
return V();
return *it;
}
void operator = (V value)
{
if (value == V())
{
container->erase(key);
}
else
{
// probably should use .insert() and conditionally assign
(*container)[key] = value;
}
}
};
std::map<K, V> _inner;
proxy operator[](K k)
{
return proxy{&_inner, k};
}
};
int main()
{
zero_map<int, int> foo;
assert (foo._inner.size() == 0);
foo[1] = 0;
assert (foo._inner.size() == 0);
foo[0] = 1;
assert (foo._inner.size() == 1);
foo[0] = 0;
assert (foo._inner.size() == 0);
}
As a comment said, use a proxy class.
template<typename T, size_t BadIndex>
class Element{ // please use a more meaningful name
public:
Element(const size_t index): index(index){}
operator T& (){return value;}
operator T const&() const{return value;}
T &operator =(const T &rhs){
if(index != BadIndex)
value = rhs;
return value;
}
operator T const&() const{return value;}
operator T&(){return value;}
private:
T value;
const size_t index;
};
class qqq{
public:
std::map<int, Element<int, 5>> core;
Element<int> &operator [](size_t index){
auto itt = core.find(index);
if(itt == core.end()){
core.emplace(index, index);
itt = core.find(index);
}
return (*itt).second;
}
};
That should work, but 5 will always give you a garbage result.
You have to always return a value which can be used as left value in the assignment expression. Therefore, I suggest to use a garbage int variable. I declared the garbage as static because we need just one instance of this variable and we don't care its value.
For example,
class qqq{
static int garbage;
map<int,int> core;
//......
int& operator[](int n){
if(CASE A && THE VALUE PASSED TO IT IS 0)
return garbage;
else
return core[n];
}
};
However, this solution is confusing in my point of view because the behaviour completely changes according to what you specify in the square brackets. If the value passed in input is incorrect, I would probably thrown an exception.
* EDIT *
I think you are over complicating the problem using the [] operator. You can easily solve your problem by using setter and getters. For example :
int set(int index, int value){
if( value == 0)
core.erase(core.find(index));
else
return core[index];
}
int get(int index) {
return core[index];
}
The [] allows only for returning a reference, you don't know what is the value used in the assignment.
You question is now clear, unfortunately you will have no way to do that is C++. operator[] is not a getter and a setter : it can only return a reference, and that reference is than used for a mere assignement. At the moment the operator returns its reference, you cannot know what value will be used for a assignement, and you can hardly know how the ref will be used.
IMHO what you need is more :
int getCore(int i) {
return core[i];
}
void setCore(int i, int newval) {
if (newval == 0) {
core.erase(core.find(i));
}
else {
core[i] == newval;
}

Overloading subscript operator for non-array elements

I have written a templates class for storing multiple bools in an integer.
Right now, setting and getting each bool is done with explicit functions
bool isBitSet(int index)
{
return static_cast<bool>((block_ >> index) % 2)
}
void setBitOn(int index)
{
block_ |= 1 << index;
}
I believe that the following would work for getting a value, but how would setting work since we can't directly return a reference for a bit?
const bool operator [] (int index) const
{
return static_cast<bool>((block_ >> index) % 2);
}
The same is done in std::vector<bool> and in std::bitset in the standard library. As stated in the reference, std::vector<bool> it returns a proxy class that has its operators overloaded to act as an element of the vector.
You could to that as well.
For a user-friendly example see again the reference for a public interface, it is something like this:
template <class Allocator>
class vector<bool, Allocator> {
// ...
public:
class reference {
friend class vector;
reference();
public:
~reference();
operator bool() const;
reference& operator=(bool x);
reference& operator=(const reference&);
void flip();
};
// ...
};
To implement this class you should store a member pointer to your actual data block and a mask to operate with.
For a real example, in the g++ headers look for member class of std::vector<bool> called std::vector<bool>::_Bit_reference in the file bits/stl_bvector.h.
To clarify the OP with an example:
Let's say you have a class containing 320 bools. You could write it as:
class boolcontainer {
uint32_t data[10];
public:
//default ctor. to initialize the elements with zeros
boolcontainer() { for (int i = 0; i < 10; ++i) { data[i] = 0; } }
}
You want to add an operator[]. To add a const one is easy:
class boolcontainer {
uint32_t data[10];
public:
bool operator[](int i) const { return data[i/32] & (1 << (i%32)); }
}
to have a non-const one you need much more. First you need to create a class that represents a reference to your value. You must have some kind of pointer to where the value is stored and (in this case) you need a bitmask to specify one concrete bit. To be able to handle this as a bool& you need to add some operators, namely conversion to bool and operator=:
class reference {
uint32_t *dataptr;
uint32_t mask;
public:
//constructor just initializing members
reference(uint32_t *dataptr_, uint32_t mask_) : dataptr(dataptr_), mask(mask_) {}
//conversion to bool
operator bool() const {
//just like in the getter, but the bitmask is stored now locally
return *dataptr & mask;
}
//sets one single bit represented by mask to b
reference& operator=(bool b) {
if (b) {
*dataptr |= mask;
} else {
*dataptr &= ~mask;
}
return *this;
}
//TODO copy ctor., operator==, operator<
};
Note that the above struct will behave as a bool& -- reading from it reads the value from the data point represented by the pointer and the mask, and similarly, writing to it overwrites the bit at the represented location. I also wrote a constructor that initializes the members.
Now all you need is that your boolcontainer's operator[] should return an object of the above class:
class boolcontainer {
uint32_t data[10];
public:
boolcontainer() { for (int i = 0; i < 10; ++i) { data[i] = 0; } }
class reference {
... //see above
}
//keep the const version for efficiency
bool operator[](int i) const { return data[i/32] & (1 << (i%32)); }
//non-const version returns our reference object.
reference operator[](int i) { return reference(&data[i/32], 1 << (i%32)); }
};
And now some code to test it (prints only the first 40 values):
#include <iostream>
#include "boolcontainer.h"
void printboolcontainer(const boolcontainer &bc)
{
//note that this is the constant version
for (int i = 0; i < 40; ++i) {
std::cout << bc[i];
}
std::cout << std::endl;
}
int main()
{
boolcontainer bc;
printboolcontainer(bc);
bc[0] = true;
bc[3] = true;
bc[39] = true;
printboolcontainer(bc);
}