c++ no matching constructor? - c++

I have to create an own string class for a university project, my code so far looks like(I only show the relevant parts):
class SuchString
{
char* str;
size_t siz;
public:
SuchString(char* a);
~SuchString();
SuchString(SuchString& a);
SuchString operator+(const SuchString& a) const;
...
...
};
As you can see I have a constructor for char* types, implemented as:
SuchString::SuchString(char* a)
{
siz = strlen(a);
str = new char[siz];
strcpy(str, a);
}
The problem is with my operator+ function:
SuchString SuchString::operator+(const SuchString &a) const
{
return SuchString(strcat(str, a.str));
}
I get the following error message:
No matching constructor for initialization of 'SuchString'
As far my understanding goes, the strcat function should return with a char*, and I have a constructor for that type.
I get the same error message for the following:
SuchString SuchString::operator+(const SuchString &a) const
{
char* lel = strcat(str, a.str);
return SuchString(lel);
}
And again, the same thing happens. I expected that the code SuchString(lel) would create a temporary variable, so the function can return with it, just as in the previous example.
Any help is appreciated.
ps: I know it's absolute nonsense to create a string class like this, but this is some small project for university.

SuchString(SuchString& a); takes a non-const reference as a parameter, so passing it temporaries is not doable. What you probably want is
SuchString(const SuchString& a);
because when you return by value, a copy is made - i.e.:
return SuchString(lel);
will create a temporary SuchString which is then copied and returned. In theory, that is, because in practice the copy is most likely optimized out.

Related

How to fix stack overflow on overloaded addition operator in c++

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/

C++ const "and the object has type qualifiers that are not compatible with the member

I'm new to C++ programming and in my OPP class we were requested to create a phone book.
Now, in the lecture the Professor said something about that if you want to make sure that your variable that is being injected to a method doesn't get changed you must put const on it.
here is my code so far.
private:
static int phoneCount;
char* name;
char* family;
int phone;
Phone* nextPhone;
public:
int compare(const Phone&other) const;
const char* getFamily();
const char* getName();
and in Phone.cpp
int Phone::compare(const Phone & other) const
{
int result = 0;
result = strcmp(this->family, other.getFamily());
if (result == 0) {
result = strcmp(this->name, other.getName);
}
return 0;
}
I keep getting "the object has type qualifiers that are not compatible with the member"
when I try to call to strcmp inside my compare function.
I know that I can just remove the const in the function declaration and it will go away, but I still doesn't understand why it's showing in the first place.
Help would be greatly appreciated.
You need to add const qualifier for getters const char* getFamily() const;. This way these getters can be invoked on objects of type const Phone & that you pass into function.
Also other.getName should be other.getName().
Your signature
int Phone::compare(const Phone & other) const
means inside that function you need to ensure you don't change the Phone instance.
At the moment, your function calls const char* getFamily() (and getName, which you've missed the () call from). Neither of these functions are const, hence the error.
If you mark these as const too, it will be ok.
In addition to the other answers that correctly suggest const qualifying your getters, you can access the data members of other directly, avoiding those calls.
int Phone::compare(const Phone & other) const
{
int result = strcmp(family, other.family);
if (result == 0) {
result = strcmp(name, other.name);
}
return result;
}

Returning a whole class of information inside a function

so I've been working on a program where I have a class called CDistance, here it is,
class CDistance
{
private:
int feet, inches;
public:
CDistance();
CDistance(int, int);
void setDist();
void printDist() const;
CDistance add(const CDistance&) const;
};
part of what I need to do is to create an array of 5 of these objects, set the feet and inches on each one of them, and then add them together without changing the original variables. This is the function definition, as you can see, it's working with all constant members, so it's a matter of figuring out how to reference the variables, but most importantly, getting them back into a CDistance type to be returned. Should I create a new CDistance type within this function to work with the ref
CDistance CDistance::add(const CDistance&) const
{
}
That's where I've been stuck, I'm kind of confused about the whole pointers and encapsulation deal. I'm new to programming, and have learned that the hard way, but if someone could help me out with this, I would really appreciate it
Should I create a new CDistance type within this function to work with the ref
Yes, you'll need a new object to modify and return:
CDistance add(const CDistance& other) const {
CDistance result = *this; // Copy this object
result.feet += other.feet; // Add the other object...
result.inches += other.inches; // ... to the copy
return result; // Return the copy
}
Note that this isn't complete; there's one deliberate error, and an unknown number of accidental errors, which you'll need to fix yourself.
You can simply return a local result instance from your function:
CDistance CDistance::add(const CDistance& other) const
{
CDistance result(*this);
// Calculate the result using result.feet, result.inches and
// other.feet, other.inches
return result;
}

Error in C++ code when overloading operators

I'm trying to overload the '+' and '=' operators in my code, but I keep getting a run time error and the program crashes when running using VS2012 but runs perfectly in borland C 3.1.
Here's my code:
class employee{
int eid;
long esalary;
char * ename;
static char company_name[20];
static int emp_count;
public:
static char * getcompanyname(){
return company_name;
}
static int getempcount(){
return emp_count;
}
void set(int empid);
void set(long empsalary);
void set(char empname[]);
int getid();
long getsalary();
char * getname();
employee(int empid=0,long empsalary=0,char empname[]="NA"){
eid=empid;
esalary=empsalary;
ename=new char[strlen(empname)+1];
strcpy(ename,empname);
emp_count++;
}
employee(employee &ref){
eid=ref.eid;
esalary=ref.esalary;
ename=new char(strlen(ref.ename)+1);
strcpy(ename,ref.ename);
}
~employee(){
delete(ename);
}
employee operator+(employee &ref){
employee temp(*this);
temp.esalary=esalary+ref.esalary;
return(temp);
}
employee& operator= (employee &ref){
eid=ref.eid;
esalary=ref.esalary;
return * this;
}
}e1,e2,emp;
then in main:
emp=e1+e2;
To be honest, your code is invalid. It should not even compile, since it violates the reference binding rules: the + operator returns a temporary object, which cannot be passed through a non-const reference to the = operator. If you managed to compile this code, it simply means that your compiler(s) accepts it as an "extension" of the language.
To fix that specific error you have to add a bunch of const qualifiers to your declarations
employee operator +(const employee &ref) const {
employee temp(*this);
temp.esalary = esalary + ref.esalary;
return temp;
}
employee& operator =(const employee &ref){
eid = ref.eid;
esalary = ref.esalary;
return *this;
}
This will make your code valid from the C++ point of view, but it probably won't fix the crash, since the reason for the crash must be elsewhere.
Here's your crash-causing error: in the copy-constructor you did this
ename=new char(strlen(ref.ename)+1);
When you allocate an array with new, you have to use [] brackets, not ()
ename = new char[strlen(ref.ename) + 1];
You did it correctly in your first constructor, but then you for some reason used () instead of [] in your copy constructor. () in this context mean something completely different: it allocates a single char and initializes it to strlen(ref.ename) + 1 value.
BTW, is there a reason you are not copying ename in the copy-assignment operator?
Also, memory allocated with new[] must be freed with delete[]. Not with delete, but with delete[]. This is what your destructor should look like
~employee() {
delete[] ename;
}
Finally, you might be much better off using std::string for storing ename, instead of relying on raw memory management. (Unless you were specifically asked to do it that way).

Not copying char arrays, function swap doesnt compile correctly and stringPtr is not modified

//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.