Operator overloading = and [] - c++

Right now, I must write
st[1];
st = 5;
What must I change in my code to be able to do this:
st[1] = 5;
#include <iostream>
using namespace std;
class A
{
public:
A(){this->z = 0;}
void operator = (int t) { this->x[this->z] = t+10; }
int& operator [] (int t) { this->z=t; return this->x[t]; }
private:
int x[2];
int z;
};
void main()
{
A st;
st[0]=9;
cout<<st[0];
system("pause");
}
UPD: Now I see 9 instead 19.

The built-in operator = expects an lvalue as its left hand operand. Therefore, in order for this statement to compile:
st[1] = 5;
You need to change the return type of your operator [] from int to int&:
int& operator [] (int t) { return this->x[t]; }
// ^^^^
You could also provide a const overload, which will return a reference to const if the object on which operator [] is invoked is const:
int const& operator [] (int t) const { return this->x[t]; }
// ^^^^^^^^^^ ^^^^^

Related

how to create an overload operator for adding a new element to the beginning or end of a vector с++

First I would like to apologize for the quality of my code, I'm just learning.
I have a university assignment.
String concatenation and adding one character to a string (like
on the left and on the right). Implement using overloading
the operator.
The question is this:
I need to implement two overloads (operator+)
First: adding one element to the end of the vector ( + 'e', ​​for example ).
Second: adding an element to the beginning of the vector ('e' + , for example).
I have problems in order to implement the second part of the assignment.
I searched similar questions on stackoverflow, but they did not help me much.
Here is my code:
#include <iostream>
#include <vector>
using namespace std;
template <class T>
class String
{
private:
public:
vector<T> ptr_string;
String() // default value constructor (empty string)
{
ptr_string.push_back('\0');
}
String(const String& other) // copy constructor of the same type
{
int n = other.getLength();
for (int i = 0; i < n; i++)
{
ptr_string.push_back(other.ptr_string[i]);
}
}
String(T symbol, int n) // n times repeated value constructor
{
for (int i = 0; i < n; i++)
{
ptr_string.push_back(symbol);
}
}
String(String&& a) // move constructor
: ptr_string(a.ptr_string)
{
a.ptr_string = nullptr;
}
int getLength() const
{
return ptr_string.size();
}
void printString() const
{
int i = 0;
for (int i = 0; i < ptr_string.size(); i++)
{
cout << ptr_string[i];
}
cout << endl;
}
template <typename T2>
auto operator+(T2 b)
{
ptr_string.push_back(b);
return ptr_string;
}
auto operator+(String const& a)
{
ptr_string.push_back(a);
return ptr_string;
}
};
int main()
{
String<char> P = String<char>('P', 10);
P + 'e';
P.printString();
'e' + P;
P.printString();
}
I tried to pass a reference to a vector as a parameter, but I ran into a problem that this is most likely not the right solution.
auto operator+( String const& a)
{
ptr_string.push_back(a);
return ptr_string;
}
String<char> P = String<char>( 'P', 10);
'e' + P;
P.printString();
expected result: ePPPPPPPPPP
First, operator+ should not modify the current object. It should not return a vector but a new String<T>. It should be const.
Your char,int constuctor misses to add a nullterminator. Maybe that was on purpose, but I changed it because I am using that constructor. Moreover, I removed the move constructor, because its not needed yet. In its implementation you assign nullptr to the vector which is wrong. You need not implement the move constructor, you can declare it as =default;. This is what I also did for the copy constructor, because the compiler generated copy constructor is as good (or better) than your self written one.
Then, there is no + for 'e'+String in your code. When implmented as member then this is always the left operand. You can implement it as free function.
#include <iostream>
#include <vector>
template<class T>
class String {
public:
std::vector<T> ptr_string;
String() { ptr_string.push_back('\0'); }
String(const String& other) = default;
String(T symbol, int n) {
for (int i = 0; i < n; i++) {
ptr_string.push_back(symbol);
}
ptr_string.push_back('\0');
}
int getLength() const {
return ptr_string.size();
}
void printString() const {
int i = 0;
for (int i = 0; i < ptr_string.size(); i++) {
std::cout << ptr_string[i];
}
std::cout << std::endl;
}
template<typename T2>
auto operator+( T2 b) const {
String res = *this;
res.ptr_string.push_back(b);
return res;
}
auto operator+( String const& a) {
String res = *this;
for (const auto& c : a.ptr_string) res.ptr_string.push_back(c);
return res;
}
};
template<typename T2,typename T>
auto operator+(const T2& b,const String<T>& a) {
return String<T>(b,1) + a;
}
int main() {
String<char> P = String<char>( 'P', 10);
auto Y = P + 'e';
P.printString();
Y.printString();
auto Z = 'e' + P;
P.printString();
Z.printString();
}
Demo
This is just minimum changes on your code. I would actually implement also the other operators outside of the class as free functions. The loop in the char,int constructor should be replaced with the appropriate vector constructor and perhaps there is more which can be improved. For more on operator overloading I refer you to https://en.cppreference.com/w/cpp/language/operators and What are the basic rules and idioms for operator overloading?
I don't think your assignment really cover a scenario that happens in real life. It is full of code smell. As #463035818_is_not_a_number mentionned operator+ usually don't modify the current object. But it is technically possible, See below. Vector are not meant to "push_front", avoid 'push_front' on vector as a general rule (here, i use deque for ex).
#include <deque>
#include <iostream>
#include <string>
template<class T>
struct ConcatenableDeq
{
std::deque<T> _deq;
ConcatenableDeq(std::deque<T> deq) : _deq(deq) {};
void print() const
{
for (const auto& e : this->_deq)
std::cout << e << " ";
std::cout << std::endl;
}
friend void operator+(ConcatenableDeq<T>& cd, const T& v)
{
cd._deq.push_back(v);
}
friend void operator+(const T& v, ConcatenableDeq<T>& cd)
{
cd._deq.push_front(v);
}
};
int main(int argc, char* argv[])
{
ConcatenableDeq<char> cd({ '1', '2', '3' });
cd.print();
cd + '4';
cd.print();
'0' + cd;
cd.print();
// output:
// 1 2 3
// 1 2 3 4
// 0 1 2 3 4
}

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';
}

How to use assignment operator on proxy of index operator

In the following code I made a template class, Its initialized in main function and I'm trying to assign char* as you can see below but It isn't working. I think the issue is in assign operator function I defined in Proxy class but I can't figure it out
#include <iostream>
using namespace std;
template <class T>
class Vector {
public:
T *p;
Vector(int size) {
p = new T[size];
}
class Proxy {
Vector &a;
int i;
public:
Proxy(Vector &a, int i) : a(a), i(i) {
}
void operator=(const T x) {
a.p[i] = x;
}
};
Proxy operator[](int i) {
return Proxy(*this, i);
}
};
int main() {
Vector<char *> sv1(2);
sv1[0] = "John";
sv1[1] = "Doe";
}
I'm getting following error;
I already tried setting parameter in assignment operator function to const, I also tried implicitly typecasting to T nothing has worked
Try this:
using namespace std;
template <class T>
class Vector {
public:
T* p;
int sz;
Vector(int size) {
p = new T[size];
sz = size;
}
template<class T>
class Proxy {
Vector<T>& v;
int i;
public:
Proxy(Vector<T>& vec, int index) :v(vec),i(index) { }
void operator= (const T val) { v.p[i] = val; }
};
Proxy<T> operator[](int index) { return Proxy<T>(*this, index); }
};
Your code will work with any basic type, (int, char, double) and pointers, but not, for example, with this:
int main() {
Vector<char*> sv1(2);
sv1[0] = "John";
sv1[1] = "Doe";
}
Firstly, the Vector points to a char*, not a string literal (const char*). You'd have to cast it using a C-style cast or a const_cast. Example:
int main() {
Vector<char*> sv1(2);
sv1[0] = const_cast<char*>("John"); //succeeds
sv1[1] = (char*)"Doe"; //succeeds
sv1[0] = "John"; //fails
sv1[1] = "Doe"; //fails
}
A string literal is always a const char* in C++.
You'll have same error writing code:
char * whatever = "something";
This code is absolutely wrong at least for string:
void operator=(const T x)
{
a.p[i] = x;
}
Step 1: allocate buffer;
Step 2: copy string to allocated buffer.
Your code is OK for primitives like char, int, etc. The following code should work:
int main() {
Vector<char> sv1(2);
sv1[0] = 'J';
sv1[1] = 'D';
}

Correct constness with pointer / object / template parameter

I have a template class foo (essentially a matrix). The template parameter for foo can only be int, float, or double, i.e., not const int. The reason for this is that I have specialized operators for these, and it seems redundant to duplicate the operators for the const cases. I have two get_data functions, which return a pointer with appropriate constness. But I also wan't a row function that selects a single row and returns a const foo, such that the caller cannot modify the returned object.
My questions:
1) How can i make B const?
2) Should I make operator functions for e.g. foo ?
2) Should I make a reference_foo class?
template <class T>
class foo
{
using uint8_t = unsigned char;
int rows = 0;
int cols = 0;
T * data = nullptr;
bool reference = false;
public:
foo() = default;
//foo(const foo&) // this is not included here for simplicity
//foo& operator=(const foo&) // this is not included here for simplicity
foo(int r, int c) : rows(r), cols(c)
{
data = new T[rows * cols];
}
~foo()
{
if (!reference)
{
delete[] data;
}
}
T * get_data()
{
return data;
}
T const * get_data() const
{
return data;
}
const foo row(int r) const
{
foo t;
t.rows = 1;
t.cols = cols;
t.reference = true;
// t.data = get_data() + r * cols; // ERROR: invalid conversion from 'const uint8_t*' to 'uint8_t*'
t.data = const_cast<T*>(get_data()) + r * cols; // Not pretty, but "ok" if the returned object is const
return t;
}
};
int main()
{
const foo<int> A(2, 1);
// A.get_data()[0] = 1; // ERROR: assignment of read-only location, perfectly catched by compiler
auto B = A.row(1);
B.get_data()[0] = 1; // B is not const... overwritten...
return 0;
}
The operator functions has been left out for simplicity.
There are 2 kinds of constness here. Const data and const handle.
What we want to do is create sanity out of the four combinations:
const handle, const data = const
const handle, mutable data = const
mutable handle, const data = const
mutable handle, mutable data = mutable
Furthermore, marking a return value as const has no meaning. A return value is an r-value. It will be either copied or moved. This will not result in a const handle at the call site.
So we need to detect constness in 2 places in respect of get_data(). C++ does the first for us with a const overload. Then we must defer to another template which is evaluated in deduced context so we can use std::enable_if:
#include <cstddef>
#include <utility>
#include <type_traits>
// default getter - element != const element
template<class Element, typename = void>
struct data_getter
{
using element_type = Element;
using const_element_type = std::add_const_t<element_type>;
// detect mutable container
element_type* operator()(element_type ** pp) const
{
return *pp;
}
// detect const container
const_element_type* operator()(element_type * const * pp) const
{
return *pp;
}
};
// specific specialisation for element == const element
template<class Element>
struct data_getter<Element,
std::enable_if_t<
std::is_same<Element, std::add_const_t<Element>>::value>>
{
// in this case the container's constness is unimportant, so
// we use const because it means only writing one method
Element* operator()(Element *const* p) const
{
return *p;
}
};
template <class T>
class foo
{
public:
using element = T;
using const_element = std::add_const_t<element>;
int rows = 0;
int cols = 0;
element * data = nullptr;
bool reference = false;
public:
foo() = default;
//foo(const foo&) // this is not included here for simplicity
//foo& operator=(const foo&) // this is not included here for simplicity
foo(int r, int c) : rows(r), cols(c)
{
data = new element[rows * cols];
}
~foo()
{
if (!reference)
{
delete[] data;
}
}
decltype(auto) get_data()
{
// defer to getter
return data_getter<element>()(&data);
}
decltype(auto) get_data() const
{
// defer to getter
return data_getter<const_element>()(&data);
}
// this will return a mutable container of const data
foo<const_element> row(int r) const
{
foo<const_element> t;
t.rows = 1;
t.cols = cols;
t.reference = true;
t.data = get_data() + r * cols;
return t;
}
};
int main()
{
foo<int> A(2, 1);
A.get_data()[0] = 1;
auto AC = A.row(0);
auto x = AC.get_data()[0]; // fine
// AC.get_data()[0] = 1; // assignment of read-only location
return 0;
}

overload operator[] on return type

There is something that is troubling my brain since a moment: I am trying to overload the [] operator based on the return type. Here is what I need to do:
class A {
private:
double* data_;
int N_;
public:
A (N=0):N_(N){
data_ = new double[N];
}
~A {delete[] data_;}
double operator[] (const int i) {
return data_[i];
}
double* operator[] (const int i) {
return &data[i]; // for example; in fact here i need to return some block of data_
}
};
This code won't compile; and that is my problem. Can someone help me to solve this problem?
PS: I know how to overload normal functions on the return type for example:
int foo ();
string foo ();
I used some tricks that I read in this forum. In this way:
struct func {
operator string() { return "1";}
operator int() { return 2; }
};
int main( ) {
int x = func(); // calls int version
string y = func(); // calls string version
double d = func(); // calls int version
cout << func() << endl; // calls int version
func(); // calls neither
}
Thank you.
Two method overloads must have different signatures. The return type is not part of the signature of a method.
You can use the same "trick" that you use for functions, that is use a proxy object with conversion operators:
class A
{
private:
double* data_;
int N_;
public:
A (int N = 0)
: N_(N), data_(new double[N])
{}
~A() { delete[] data_; }
struct proxy
{
int i;
double * data;
operator double() const
{
return data[i];
}
operator double*()
{
return &data[i];
}
operator double const *() const
{
return &data[i];
}
};
proxy operator[] (int const i) {
proxy p { i, data_ };
return p;
}
proxy const operator[] (int const i) const {
proxy p { i, data_ };
return p;
}
};
int main()
{
{
A a(12);
double d = a[0];
double * pd = a[0];
}
{
A const ca(12);
double d = ca[0];
//double * pd = ca[0]; // does not compile thanks to overloads on const
double const * pcd = ca[0];
}
}
However, I would argue that this is a terrible idea. Having your operator[] return either a value or a pointer to this value is guaranteed to confuse the users of your class, in addition to making it impractical to use in expressions where both types are possible. For instance, std::cout << a[0]; would not compile (ambiguous overloads).
Probably you need something like that:
class A {
private:
double* data_;
int N_;
... // other stuff
public:
double operator[] (const int i) const { // note const here
return data_[i];
}
double& operator[] (const int i) { // note reference here
return data_[i];
}
};
also operator should be public to have a sense.