I'm trying to learn the concept of operator overloading in c++ but I have got stuck on a problem that I'm trying to solve using the operator+ where in the my main-function I add to userdefiend classes together.
The class constructor takes a string pointer as a parameter.
My understanding of the operatoroverloading concept is that you declare a function in a class, using the keyword operatorX, and replace X with the operator that you will like to overload. Like if i would like to overload the '-' operator I should write like this operator-. But when I debug my code it results in an Stack overflow and the program stops.
The class looks as follows:
class Hello{
public:
Hello(string str):pstr(&str){
}
//The overloaded function below
Hello operator+(Hello& h1){
Hello temp(*this);//creates a copy of the current Hello-object
temp = temp + h1;//adds the new value to the temporary object
return temp;
}
private:
string* pstr;//pointer to string-object
}
I know that i get the stack overflow in the overloaded function.
In the main method i have the following code:
void main(){
Hello h1("Hello ");
h1 + Hello("World");
}
I'm not shore that i've coded this in the right way but the result should be Hello World in the return object if i'm not mistaken.
How can I solve this so that I dont get the stack overflow when the code is running, and also how can I get the right return value?
in
Hello operator+(Hello& h1){
Hello temp(*this);//creates a copy of the current Hello-object
temp = temp + h1;//adds the new value to the temporary object
return temp;
}
the operator+ recursively calls itself, you have to really implement the addition
probably you wanted :
Hello operator+(const Hello& h1) {
Hello temp(*pstr + *(h1.pstr))
return temp;
}
Out of that, why do you have pstr as a pointer to a std::string rather than to have just a std::string str; ?
It is much more practical to have for instance :
class Hello{
public:
Hello(string s) : str(s) { }
Hello operator+(const Hello& h1){
Hello temp(str + h1.str);
return temp;
}
private:
string str;
};
Note if you really want to have string* pstr; your constructor
Hello(string str):pstr(&str){}
is wrong because you save the address of the parameter, you need to change it to for instance :
Hello(string str) : pstr(new string(str)) {}
and having a pointer you need to add the destructor to delete the string, and the copy constructor, the operator= etc look at rule_of_three
In operator overloading, the key concept to think is how would the behavior be if the type you were defining was a primitive type. For example, what would adding a pointer to string with another pointer to string look like.
As mentioned above, your definition is recursively calling operator+.
Here is an example that might be useful: https://www.geeksforgeeks.org/operator-overloading-c/
Related
Sorry. i do not know how to ask this question, so i will give a example.
Get the arg string from the command line
Example: MyProgram.exe -logs=yes -console=no
CmdLine CmdLine( ::GetCommandLine() ); // Get arg string.
When i have the arg string. i wish to look for "logs" ("yes") and "console" get its value
("no").
CmdLine.GetKey["logs"].GetValue(); // Get the value of "logs".
CmdLine.GetKey["console"].AsBool(); // Get the value of "console".
I have to overload the [] operator ( void operator[] ( const std::string & str ); )
GetKey["logs"]; // okay.
But i do not know how or if i can in C++ to do something like;
CmdLine.GetKey["console"].MyFunction(); // HOW to do this?
How can i tell "GetKey" to call "MyFunction(). (sorry for bad wording. but i do not know know
what this is called.
Thank you for patients and help and ideas.
EDIT:
Sorry for confusion!
CmdLine.GetKey["logs"].GetValue(); // Example!!!
I overload the [] so i can look up "logs" in a std::map, std::unordered_map (whatever).
When i find "logs" i wish for "GetKey["logs"]" to call "GetValue()" and return
the value.
I do know know what this is called when i do this;
Func().SomeFunc().SomeOtherFunc();
Because i want to do the example i tried to explain.
Lets dissect it step by step:
CmdLine.GetKey["logs"].GetValue();
// call method on some object
// call operator [] on GetKey
// GetKey is a member of CmdLine
As mentioned in a comment, GetKey is not a good name for a member. I suppose you don't really need it, but it was just your attempt to express that you are looking up the object on which you want to call GetValue() in CmdLine. I have to admit, I don't fully understand the example. Anyhow...
You can make operator[] return an object that has a member function that you can call:
#include <iostream>
struct foo {
std::string value;
void print() { std::cout << value; }
};
struct bar {
foo operator[](const std::string& x) {
return {x};
}
};
int main(int argc, char *argv[])
{
bar b;
b["hello world"].print();
}
Output:
hello world
For more on operator overloading read What are the basic rules and idioms for operator overloading?.
First i want to introduce my situation :
I have write some classes that has char* pointer as private class member.And also this project has GUI, so when click buttons,some functions may execute more than one time.Those classes are designed single class in project.But some functions of them can execute more than one time.Then I found my project has memory leak.
so i want to ask the following questions:
how to design the set function?
how to design the other functions that use the char* member variable?
how to design the class operator= function?
for example:
class A:
{
public :
setStr(char * s){//need new or just use =?};
A & operator=(const A& other){//also need new?};
manyTimesFunctions(char * other)
{
//need to use chars other to assignment str
//how to carefully use new to avoid memory leak?
//other may be another class's locality none const variable
}
private:
char * str;
}
So ,the project only init class A once,but may use setStr and manyTimesFunctions many times.
May be the answer:
I think i have found what i need to take care of:copy that class,that answers are really useful to me.
Just use std::string. It takes care of memory management for you. The member declaration then looks like
std::string str;
and the setter function looks like
void setStr( char const* s ) { str = s; }
Where you want to use the string and need a char const*, just write str.c_str().
With use of standard library types like std::string, and no manual dynamic allocation, you generally don't need to be concerned about operator=: the compiler-generated copy assignment works nicely.
By the way, it's generally a good idea to decide on some naming convention for member variables. Common ones for C++ include str_, mStr, and my_str. The underscore suffix is perhaps the most common one, but don't use a leading underscore like _str, because although technically allowed it conflicts with the conventions for implementation defined names (e.g. leading underscore is not allowed for identifiers in the global namespace).
I am not 100% sure what you are trying to do. However, since char* is a pointer you may be able to simply pass around the references.
char* operator=(char* s) { str = s; }
Just know that then if you modify value in your function it will modify the place you copied it from
If the char* needs to actually be a clone, so that it does not modify the original value. You first need to obtain the length of the char*.
This can be done with this function
unsigned Length(char* s)
{
unsigned I = 0;
while( *(s+I) != '\0')
I++;
return I;
}
The a new string can be created as follows
str = new char[LENGTH];
At that point you can copy the string over term by term
for(I = 0 ; I < LENGTH; I++)
{
str[I] = s[I];
}
Finally to avoid memory leaks this needs to be deleted in the class destructor
~A()
{
delete [] str;
}
Of course using std::string could save a lot of problems.
This answer will be used to contrast what the other answer(s) given that state to use std::string (and those answers are correct -- use std::string).
Let's assume that you could only use char *, you can't for some reason use std::string, and that you are dealing with NULL terminated strings. This is a synopsis of what your implementation would have to do (and please compare this with simply using std::string):
#include <algorithm>
#include <cstring>
class A
{
public:
// construct empty string
A () : str(new char[1]()) {}
// construct from non-empty
A(const char *s) : str(new char[strlen(s) + 1])
{ strcpy(str, s); }
// copy construct
A(const A& rhs) : str(new char[strlen(rhs.str) + 1])
{ strcpy(str, rhs.str); }
// destruct
~A() { delete [] str; }
// assign
A& operator=(const A& rhs)
{
A temp(rhs);
std::swap(str, temp.str);
return *this;
}
// setter
void setStr(char * s)
{
A temp(s);
*this = temp;
}
// getter
const char* getStr() { return str; }
private:
char * str;
};
Live Example
After adding a couple more constructors and a getter function, this follows the Rule of 3.
You see how much code we needed to add just to make the class safely copyable and assignable? That's why using std::string is much more convenient than using char * when it comes to class members. For std::string a single line needs to be changed, compared to adding the copy / assignment (and move, which I didn't show) functions.
The bottom line is that in C++ if you want strings, use strings (std::string) and try to keep away from using char * (unless you have a very compelling reason to be using char * to represent string data).
I have a simple class called String which has as a private field a char*.
class String {
char *s;
+ some public methods
};
I want to overload the + operator so a + b would mean that the strings from a and b are concatenated.
The function is here:
String String::operator+(String a)
{
String rez;
rez.s = new char[strlen(this->s) + strlen(a.s) + 1];
assert(rez.s);
strcpy(rez.s, this->s);
strcat(rez.s, a.s);
cout<<rez.s<<endl; // HERE rez.s CONTAINS THE RIGHT STRING!
return rez;
}
After I call this:
c = a + b;
i get an error called Debug assertion failed.
Any ideas?
First, read up on the Rule of Three
Then, consider this:
class String {
char *s; // << pointer
+ some public methods
};
"+ some public methods" better have a constructor that initializes the pointer member to a testable value (like NULL) or you're well-into undefined behavior. It better override the copy-constructor and assignment operators to properly duplicate the string from one String object to another. Finally, it better have a destructor that knows how to clean up a dynamic pointer to the content allocated in all of the above.
I strongly suggest you read that article backwards and forwards.
I need help on my homework assignment.I need to write the code for a parking garage. and in order to write it I need to copare the input of my instance of the class"Parkbox",which has been created on the on the heap and via another class "Parkinggarage" , with a #define EMPTY "--------".
So this is my code:
the Parkbox definition:
class Parkbox{
char *license_plate; // car's license plate
public:
Parkbox(); //Default CTOR
Parkbox(char * ); // CTOR
~Parkbox(); // DTOR
void show();
};
and ParkingGarage:
class ParkingGarage{
Parkbox ***p2parkboxes;
and my CTOR or ParkingGarage in order to create Parkbox instance on the heap:
ParkingGarage::ParkingGarage(const int rw,const int clm, const int plns){
p2parkboxes = new Parkbox **[plns];//points to the floors and make the arraq of p2p same size as number as floors
for(int p=0;p<plns;p++){
p2parkboxes[p]= new Parkbox *[plns];//for each Plane creats an array of pointer that is same with the num of rows
for(int r=0;r<rw;r++)
p2parkboxes[p][r]= new Parkbox [clm];
}
}
void ParkingGarage::find_next_free_parking_position()
{
for(int f=0;f<dimensions_of_parkhouse[0];f++){
for(int r=0;r<dimensions_of_parkhouse[1];r++){
for (int c=0;c<dimensions_of_parkhouse[2];c++){
//p2parkboxes[f][r][c] is the instance of the class Pakbox
if(p2parkboxes[f][r][c]==EMPTY)
{
next_free_parking_position[0]=p;
next_free_parking_position[1]=r;
next_free_parking_position[2]=c;
}
}
}
}
}
how ever at the point "p2parkboxes[f][r][c]==EMPTY" it gives me error that " no operator "==" matches these operands", .
then how can I compare a class instance directly with another variables like EMPTY?
I do not know if I am clear for you or not.
But please help me because if I do not solve this problem I can not continue completing my code.
In general, you can only compare two same types. With operator overloading, you can define your own compare operator to work with this problem. C++ cannot compare two classes in default though.
So it seems in your code that you are comparing char* type with your class type. You should compare char* with another char*. If it's treated as string, you should use strcmp for increased safety
You'll have to create a matching operator overload. The compiler error should name you the parameters, but the member should most likely look a bit like the following:
bool Pakbox::operator==(const char *other) {
return !strcmp(other, this->memberstring);
}
Note that memberstring has to be replaced by an actual member holding what's in that lot.
//In header file: class definition:
class myString
{
public:
myString(void);
myString(const char *str);
myString(const myString &); //copy constructor
~myString(void); //destructor
void swap(myString &from);
private:
char *stringPtr;
int stringLen;
};
//in cpp file, defining them member functions
myString::myString(const char *str)
{
stringLen = strlen(str);
stringPtr = new char[stringLen+1];
strcpy(stringPtr,str);
cout << "constructor with parameter called"<<endl;
}
myString::myString(const myString &str)
{
stringPtr = new char[str.stringLen +1];
strcpy(stringPtr,str.stringPtr);
cout << "copyconstructor"<<endl;
}
void myString::swap(myString &from)
{
myString buffer(from);
int lengthBuffer = from.stringLen;
from = new char[stringLen+1];
from.stringLen = stringLen;
strcpy(from.stringPtr, stringPtr);
stringPtr = new char[lengthBuffer+1];
stringLen = lengthBuffer;
strcpy(stringPtr,buffer.stringPtr);
}
You can't modify a reference. Even if you replace it with a pointer modifying a pointer will not modify an object pointed to. Instead you need to work through the reference - just swap the fields.
void myString::swap(myString &from)
{
std::swap( stringLen, from.stringLen );
std::swap( stringPtr, from.stringPtr );
}
the above is using std::swap() as suggested by user sbi in comments. This is completely equivalent to the following (just for illustration, don't reinvent STL):
void myString::swap(myString &from)
// First remember own length and pointer
const int myOldLen = stringLen;
char* myOldPtr = stringPtr;
// now copy the length and pointer from that other string
stringLen = from.stringLen;
stringPtr = from.stringPtr;
// copy remembered length and pointer to that other string
from.StringLen = myOldLen;
from.StringPtr = myOldPtr;
// done swapping
}
Both will work even when called fro self-swapping:
myString string;
string.swap( string );
You have already gotten a few good answers concerning the errors in you myString::swap() function. Yet, I'd like to add another one. There's some many things wrong with that function, I first found it hard to think of where to begin. But then I realized that you fail on some fundamental issue which I'd like to point out:
As a convention, a function called swap is expected to perform its task
in O(1)
without ever throwing an exception.
(Yes, I know, there are exceptions: std::tr1::array<>::swap(). But those should be very well justified.) Your implementation fails on both accounts. It is O(n) (strcpy) and might throw an exception (new) -- and it does so unnecessarily and without justification.
When you look at myString, you'll see that it only has two pieces of member data, which both are of built-in type. That means swapping two objects of this class is really simple to do while keeping to the conventions mentioned above: just swap the member data. That's as simple as calling std::swap on them:
void myString::swap(myString &from)
{
std::swap(this->stringPtr,from.stringPtr);
std::swap(this->stringLen,from.stringLen);
}
This is will never fail (swapping two pointers and two integers cannot fail), executes in O(1), is very easy to understand (well, once you get a grip on that swapping, anyway; it is an idiomatic form of implementing a class-specific swap function), and consists of two lines of code calling something well-tested in the standard library instead of 8 lines of code doing error-prone (and, in your case, erroneous) manual memory management.
Note 1: Once you've done this, you should specialize std::swap to call your implementation for your class:
namespace std { // only allowed for specializing function templates in the std lib
template<>
inline void std::swap<myString>(myString& lhs, myString& rhs)
{
lhs.swap(rhs);
}
Note 2: The best (simple, exception-safe, and self-assignment-safe) way to implement assignment for your class is to use its swap:
myString& myString::operator=(const myString& rhs)
{
myString tmp(rhs); // invoke copy ctor
this->swap(tmp); // steal data from temp and leave it with our own old data
return *this;
} // tmp will automatically be destroyed and takes our old data with it
from = new char[stringLen+1]; should be from.stringPtr = new char[stringLen+1]; . Also remember to free the previously allocated memory before allocating new one.
Look closely at the line
from = new char[stringLen+1];
It is the same as
from = MyString(new char[stringLen+1]);
so your constructor of MyString get uninitialized array of chars. Then you trying to get the length of the string, but strlen just looping through chars of the string looking for 0 char. As we don't know what content uninitialized array of chars might have, we don't know what length strlen could return. It can even go further than array boundary and crash your program with segfault. But I can say for sure, after that there's not enough space in from.stringPtr to hold the string you want to copy in it.
So, use from.stringPtr = new char[stringLen+1]; or better from = MyString(*this); since you have copy constructor already.