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.
Related
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/
I'm learning C++ inheritance and i have some problems with it.
I'm using Zinjal IDE with GNU c++ compiler.
This is the code:
class String {
protected:
char str[MAX_STR_SIZE];
public:
String(char str_init[])
{
strcpy(str, str_init);
}
};
class PString : String
{
public:
PString(char str_init[])
{
if (strlen(str_init) > MAX_STR_SIZE)
strncpy(str, str_init, MAX_STR_SIZE-1);
else
String(str_init);
}
};
Well it's just creating my own "string" class. But: What is the problem? The string can go too much bigger. So when the constructor of my "String" Class is called with a string the superssed "MAX_STR_SIZE" (which is defined as 80 chars for expamle) the program will crash with an array overflow ( >80 chars).
So i want to create a "child" or "derived" class called "PString" which can handles overflow.
As you can see PString child Class constructor checks the string if it's > MAX_STR_SIZE. If it's bigger than what char array can handle it cut off the string by MAX_STR_SIZE, so avoiding the overflow. If its smaller than MAX_STR_SIZE it calls the Parent class constructor.
But, g++ fails telling me "No matching function call to 'String::String()'.
It's a lame error i know, but i'm just learning
Thanks in advance.
You can't just call a constructor out of the blue. There are only specific places you can call a constructor and this isn't one of them.
The compiler sees String(str_init); and ssumes it is a function call but you don't have a matching function - hence the error.
As per the comment below there is a subtlety here. The error message is "No matching function call to 'String::String()". In a class called String a method called String is going to be a constructor. Therefore the line String(str_init); isn't a function call, it is trying to make a String item using a non-existent default constructor.
what you are trying to do does not require this set of complications. In general strncpy will handle both cases correctly. However, for the education sake here is some analysis
1.In your constructor of the PString you call the construct of the String and ask it to strcpy str_intit into str. So, you cause the same memory corruption you wanted to avoid. you are missing String() constructor. I suggest to create the default constructor for the String and remove the one you use from PString.
String() {str[0] = 0;}
..
PString(char str_init[])
{
2.your case could be modified a bit as the following:
if (strlen(str_init) > MAX_STR_SIZE) {
strncpy(str, str_init, MAX_STR_SIZE-1);
str[MAXLEN-1] = 0; // strncpy will not add '0' in this case. you need to do it yourself
}
else
strcpy(str, str_init);
above, in the if clause you use strncpy whether after the 'else' you can use the simple strcpy. So, it looks like this:
#include <cstring>
#define MAX_STR_SIZE 80
class String {
protected:
char str[MAX_STR_SIZE];
public:
String(char *str_init)
{
strcpy(str, str_init);
}
String() {
str[0] = 0;
}
};
class PString : String
{
public:
PString(char str_init[])
{
if (strlen(str_init) > MAX_STR_SIZE) {
strncpy(str, str_init, MAX_STR_SIZE-1);
str[MAX_STR_SIZE-1] = 0;
}
else
strcpy(str, str_init);
}
};
2 Errors.
First, you need to invoke the base constructor via your class' initializer list as explained in this answer.
Second you need to assign some object to your class when calling
String(str_init);
The following code compiles on my machine.
#include <cstring>
#define MAX_STR_SIZE 20
class String {
protected:
char str[MAX_STR_SIZE];
public:
String(char str_init[])
{
std::strcpy(str, str_init);
}
};
class PString : String
{
public:
PString(char str_init[]) : String(str_init)
{
if (strlen(str_init) > MAX_STR_SIZE)
strncpy(str, str_init, MAX_STR_SIZE-1);
else
String s = String(str_init);
String s2(str_init);
int i = 0;
i++;
}
};
I have been given this definitions, the function should return what is in info->phrase. However info->phrase can contain a string in which case I can only make it return the first char on info->phrase. Is there a way to make a string compatible with the char type? I am new to c++.
struct rep_info {
int num;
char *phrase;
};
I´ve tried few thing but get type errors, this was my latest attempt
char *phrase_info(rep_info info) {
char text[std::strlen(info->phrase) + 1];
text = info->phrase;
return text;
}
Since you said you have been given these definitions, let's fix the problem with the current setup first. Looking at your function, you are trying to copy into this local array (incorrectly I might add), and return this local variable. There are a number of things wrong with this, including the syntax and the fact that the local variable is destroyed when the function exits.
If you just need to get the value of the phrase member variable, the simplest solution would be to just access the member variable directly and return it:
char *phrase_info(rep_info info) {
return info.phrase; //since info is not a pointer, use the '.' accessor
}
If you mean to pass a pointer to the function, you would re-write it like this:
char *phrase_info(rep_info *info) {
return info->phrase;
}
But it seems like you feel the need to copy the contents of info->phrase into a new memory space? If so, then you would do something like this where you first allocate new memory and return this buffer:
char *phrase_info(rep_info *info) {
char *buf = new char[std::strlen(info->phrase) + 1];
std::strcpy(buf,info->phrase); //copies info->phrase into buf
return buf;
}
You would then need to use delete on the returned memory value to clean up the memory allocated by new, otherwise you will have a memory leak.
Overall, all the above solution would potentially solve the problem given some parameters you haven't made clear. To round this out, this should be written more like:
class rep_info {
private:
int num;
std::string phrase;
public:
rep_info(int n, std::string p) : num(n), phrase(p) {}
std::string get_phrase() { return phrase; }
// other functions
};
//later in the code
rep_info info(...);
info.get_phrase();
Ideally, you would wrap these member variables into their own object with corresponding member functions that can get and set these values. Moreover, for handling strings in C++, std::string is the preferred option for storing, copying, modifying, etc. strings over the older char * C-style string.
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 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.