0

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

mch
  • 9,424
  • 2
  • 28
  • 42
Dan
  • 29
  • 3
  • there is no operator for `'e' + String` in your code. When implemented as member, `this` is always the left hand side. – 463035818_is_not_an_ai Dec 30 '22 at 11:23
  • You should both your operators outside of the class (make them friends if required). As stated above, you cannot have an operator+ with a char on the lhs unless you define the operator outside of the class. – john Dec 30 '22 at 11:33
  • 3
    See [What are the basic rules and idioms for operator overloading?](https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading) – molbdnilo Dec 30 '22 at 11:38

2 Answers2

0

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?

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
0

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
}

pepece
  • 360
  • 5
  • 17
  • I'm very sorry, but i tried compiling the code and on this line of code it gave an error ConcatenableDeq cv({ '1', '2', '3' }); Error C2665 'ConcatenableDeq::ConcatenableDeq': none of the 3 overloads could convert all the argument types I don't quite understand what the problem is, so can you suggest what i am doing wrong? – Dan Dec 30 '22 at 13:57
  • @Dan Which compiler are you using? – pepece Jan 02 '23 at 09:21
  • Yes, something about not inheriting the allocator of the deque class.It is probably better not to inherit a std class (i edited my code).But that shows well that adding functionnality to std class is a code smell. – pepece Jan 02 '23 at 09:38