declaration is incompatible, beginner c++ - c++

I just need a little help on this assignment. I have to redefine operators to work with strings. I'm starting with the == operator and I have it declared in my header file, however when I go to define the function in my cpp file, it says it's incompatible with the declared function. It's probably a stupid mistake, I just don't understand this sometimes.
string.h header file
#pragma once
#include <iostream>
#include <string>
using namespace std;
#define NOT_FOUND -1
// C++ String class that encapsulates an ASCII C-string
class String
{
public:
// Default constructor
String();
// MUST HAVE: Copy-constructor that performs deep copy
String(const String& source);
// Init-constructor to initialize this String with a C-string
String(const char* text);
// Init constructor, allocates this String to hold the size characters
String(int size);
// Destructor
~String();
bool& compareTo(const String& cmp1);
// Assignment operator to perform deep copy
String& operator = (const String& source);
// Assignment operator to assign a C-string to this String
String& operator = (const char* text);
// Returns a reference to a single character from this String
char& operator [] (int index) const;
// Comparison operators
bool operator == (const String& compareTo) const;
string.cpp file
#include "string.h"
#include <string>
#include <sstream>
using namespace std;
// Default constructor
String::String()
{
Text = NULL;
}
// MUST HAVE: Copy-constructor that performs deep copy
String::String(const String& source)
{
Text = NULL;
// Call the assignment operator to perform deep copy
*this = source;
}
// Init-constructor to initialize this String with a C-string
String::String(const char* text)
{
Text = NULL;
// Call the assignment operator to perform deep copy
*this = text;
}
// Init constructor, allocates this String to hold the size characters
String::String(int size)
{
Text = new char[size];
}
// Destructor
String::~String()
{
delete[] Text;
}
// Assignment operator to perform deep copy
String& String::operator = (const String& source)
{
// Call the other assigment operator to perform deep copy
*this = source.Text;
return *this;
}
// Assignment operator to assign a C-string to this String
String& String::operator = (const char* text)
{
// Ddispose of old Text
delete[] Text;
// +1 accounts for NULL-terminator
int trueLength = GetLength(text) + 1;
// Dynamically allocate characters on heap
Text = new char[trueLength];
// Copy all characters from source to Text; +1 accounts for NULL-terminator
for ( int i = 0; i < trueLength; i++ )
Text[i] = text[i];
return *this;
}
***bool& String::operator ==(string cmp2)***
{
};

Your compareTo declaration has const while definition has no const, which means they have definition has different signature with declaration:
bool& compareTo(const String& cmp1);
^^^
bool& String::compareTo(string cmp2)
{
};
BTW, why does your compareTo return bool& ?
Also should avoid using namespace std; in any header files. see why-is-using-namespace-std-considered-a-bad-practice-in-c

Related

Compiler error "Pointer being freed was not allocated" only while using a foreach loop of custom objects in C++

I have an assignment where I build my own my string class. I made several MYString objects and put them in a vector. When I access the vector through subscript operator, I have no issue. But when I traverse through the vector using foreach loop, then I get a weird error ""Pointer being freed was not allocated"
Did I mess up my copy constructor?
Is my destructor and clear() function messed up?
header file is as follows:
class MYString{
friend std::ostream& operator<<(std::ostream&, const MYString&);
friend std::istream& operator>>(std::istream&, MYString&);
private:
static const int INITIAL_CAP = 20;
char* str;
static int getLength(const char*);
int cap; //capacity of the char array, in multiples of 20
int end; // location of the null terminator
int compareTo(const MYString& rhs);
void clear(); // to manually free memory
static int requiredCap(int end);
public:
MYString();
MYString(const MYString& mystr);
MYString(const char*);
~MYString();
MYString& operator=(const MYString& rhs);
char& operator[](int index);
const char& operator[](int index) const;
int length() const;
int capacity() const;
const char* c_str();
MYString operator+(const MYString& rhs);
int operator==(const MYString& rhs);
int operator>(const MYString& rhs);
int operator<(const MYString& rhs);
};
Here is some relevant function defintions
MYString::MYString(const MYString& rhs){
*this = rhs;
}
MYString& MYString::operator=(const MYString& rhs){
if (this == &rhs){
return *this;
}
clear();
cap = rhs.cap;
end = rhs.end;
str = new char[cap];
for (int i = 0; i < end; i++){
str[i] = rhs[i];
}
str[end] = '\0';
return *this;
}
MYString::~MYString(){
clear();
}
void MYString::clear(){
cap = 0;
end = 0;
delete[] str;
str = nullptr;
}
The main method is as follows:
#include "MYString.h"
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
int main(){
ifstream input;
input.open("file.txt");
if (input.fail()){
cout << "File error" << endl;
}
MYString s;
vector<MYString> v;
int count = 0;
v.push_back(MYString());
int index = 0;
while (input >> s){
if (count == 2){
v.push_back(MYString());
count = 0;
index++;
}
if (count < 2){
v[index] = v[index] + s;
count++;
}
}
for (MYString& str : v){
cout << str << endl;
}
Serious problem with your constructor:
MYString::MYString(const MYString& rhs){
*this = rhs;
}
Inside the body of your object, your data is not initialized, but you dereference this and assign to it. The data members contain garbage, including the pointer. In the assignment operator, you call clear, which calls delete[] on this garbage pointer. This is undefined behavior.
Implementing a constructor in terms of assignment is always wrong. Assignment is for replacing state of an initialized object with new state, while constructors provide initial state to uninitialized members. The object's lifetime has not even started UNTIL the constructor completes. Calling functions on an object whose life has not officially started is undefined behavior.
Your copy constructor needs to allocate memory and copy the data into it, similar to what you did in your assignment operator, but not cleaning up the old state first. Also, consider using strcpy instead of a loop to copy bytes. It will be faster.

strcpy not working with string pointer in a class

I'm new to c++.I made a simple program that name members of class based on your input.
But for some reason, compiler shows this error - 'str': is not a member of 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>', I have trouble understanding what it means.
Please help me out
here is my code -
#include <iostream>
#include <string>
#include <vector>
class mystring
{
private:
std::string *str;
public:
//constructors
mystring();
mystring(const std::string &strthing);
~mystring();
//methods
void display() const;
};
mystring::mystring() //defalt constructor
:str(nullptr)
{}
mystring::mystring(const std::string& strthing) //copy constructor
:str(nullptr)
{
delete str;
str = new std::string;
strcpy(this->str, strthing.str);
std::cout << "overloaded\n";
}
mystring::~mystring() //destructor
{
delete [] str;
}
void mystring::display() const //display func
{
std::cout << *str;
}
int main()
{
mystring thing;
mystring object{ "samurai" };
object.display();
}
I think something is wrong with the strcpy() function in overloaded constructor.
Thanks
There is nothing wrong with strcpy, but with how you use it. std::strings can be copied with their operator=:
std::string a;
std::string b;
a = b; // copy b to a
strcpy on the other hand is for c-strings, which a std::string is not:
char* strcpy( char* dest, const char* src );
It is unclear why you have a member of type pointer to std::string. You should either use a std::string (no pointer), or if this is an exercise to write your own string class (not an easy one!) then you should probably store the data in an array of chars.
The error you get is about strthing.str. Here strthing is a std::string which has no str member. If that constructor is supposed to be a copy constructor it should take a const mystring& as parameter not a const std::string&.
This is just a typo.
mystring::mystring(const std::string& strthing)
Should be
mystring::mystring(const mystring& strthing)
You don't use strcpy to copy std::string objects. Here's your constructor rewritten correctly (it's not a copy constructor because it doesn't copy mystring objects)
mystring::mystring(const std::string& strthing) // constructor from std::string
: str(new std::string(strthing)) // allocate new string by copying from strthing
{
std::cout << "overloaded\n";
}
Because your class allocates memory (not sure why it does but it does) you do actually need to write a genuine copy constructor and assignment operator
mystring::mystring(const mystring& strthing) // copy constructor
mystring& mystring::operator=(const mystring& strthing) // assignment operator
But I'll leave that to you.
Ther is a C++ trap between C++ type std::string and C type 'char*'.
std::string can convert to char* using std::string.c_str().
And strcpy takes char* and char const * as parameters.
In moderen C++ practice, use std::string usually, std::string * is not recommended to use.
If you want to use strcpy with std::string, you have to do the conversion between char * and std::string. Below is a simple Example:
std::string dest;
std::string source = "Hello, World!";
char temp[40];
strcpy(temp, source.c_str());
dest = temp;

overload array operator for mystring class

I need help figuring out how to overload the array operator for a MyString class that I have to create. I already have everything else figured out, but the arrays are giving me trouble, for some reason.
Here is my header file:
#ifndef MYSTRING_H
#define MYSTRING_H
#include <iostream>
#include <cstring> // For string library functions
#include <cstdlib> // For exit() function
using namespace std;
// MyString class: An abstract data type for handling strings
class MyString
{
private:
char *str;
int len;
public:
// Default constructor.
MyString()
{
str = 0;
len = 0;
}
// Convert and copy constructors.
MyString(char *);
MyString(MyString &);
// Destructor.
~MyString()
{
if (len != 0)
delete [] str;
str = 0;
len = 0;
}
// Various member functions and operators.
int length() { return len; }
char *getValue() { return str; };
MyString operator+=(MyString &);
MyString operator+=(const char *);
MyString operator=(MyString &);
MyString operator=(const char *);
bool operator==(MyString &);
bool operator==(const char *);
bool operator!=(MyString &);
bool operator!=(const char *);
bool operator>(MyString &);
bool operator>(const char *);
bool operator<(MyString &);
bool operator<(const char *);
bool operator>=(MyString &);
bool operator>=(const char*);
bool operator<=(MyString &);
bool operator<=(const char *);
MyString operator [](MyString *);
// Overload insertion and extraction operators.
friend ostream &operator<<(ostream &, MyString &);
friend istream &operator>>(istream &, MyString &);
};
#endif
What would the body look like for MyString::operator []?
MyString MyString::operator [](MyString *)
{
... what goes here
}
The syntax for using the array operator with an object of the given class is:
MyString s("Test");
char c = s[0];
The argument to the function is an integral value.
Hence, the operator needs to be declared as:
// The non-const version allows you to change the
// content using the array operator.
char& operator [](size_t index);
// The nconst version allows you to just get the
// content using the array operator.
char operator [](size_t index) const;
MyString MyString::operator [](MyString *)
That's not how you should typically use a subscript operator.
What do you expect when you are using the [] operator? By the way you declared it, you are using a string pointer as argument, and receiving a string as return.
Usually, you pass an index type (commonly an unsigned-integer like size_t) and return the character at that position. If that's what you want, you should do something along these lines:
char& MyString::operator [](size_t position)
{
// some error handling
return str[position];
}
char MyString::operator [](size_t position) const { /* ... */ }
For overall guidelines on overloading operators, take a look at What are the basic rules and idioms for operator overloading?.
Also, I would point out that your destructor is a bit odd:
if (len != 0)
delete [] str;
str = 0;
len = 0;
Your indentation level suggests that you expect everything to happen inside the if statement, but only the first one will. That is not particularly dangerous in this case, because only the delete would suffice.
There is no problem in deleteing a null pointer, and str and len will be destroyed shortly after, so you don't have to bother resetting them.

Overloading assignment operator with Classes and Vectors

I have a class defined:
#ifndef _STRINGCLASS_H
#define _STRINGCLASS_H
using namespace std;
#include <iostream>
#include <vector>
class String {
protected:
int length;
vector<string> buf;
public:
String();
String(const char* input);
String(char input);
String(int input);
String(const String& input);
String(char input, int input2);
String& operator=(const String& input);
};
#endif
and am trying to overload the assignment operator by such:
String& operator=(const String& input) {
buf = input.buf;
length = input.length;
return *this;
}
and I get the error code that buf is protected and length is protected. I'm not sure what I am missing. How can I properly overload the assignment operator with vectors and ints?
You do not need to provide any special member functions for your class, because the compiler synthesized ones will do the right thing in this case. The best option is to remove the assignment operator and copy constructor from your class definition.
class String
{
protected:
int length;
vector<string> buf;
public:
String();
String(const char* input);
String(char input);
String(int input);
String(char input, int input2);
};
You need to define the implementation as part of the class. You are missing the class specifier:
// vvvvvvvv
String& String::operator=(const String& input) {
buf = input.buf;
length = input.length;
return *this;
}
As written, you are defining a free operator overload (not bound to a class), and it's actually invalid to declare a free assignment operator overload anyway.
From the perspective of a free operator overload that isn't a member of String, buf and length are indeed inaccessible because they are private.

Copy constructor calls destructor c++

I have a test class of my to make my own string functions. I have a problem with the copy destructor.
I have 2 strings: s1 and s2.
I call the function s3 = s1 + s2;
It first calls the operator+ function and when it's finished it calls the destructor. Because of this the string object in the operator= function is empty. How can I fix this?
Destructor:
String::~String() {
if (this->str)
delete[] str;
str = NULL;
len = 0;
}
Copy Constructor:
String::String(const String& string) {
this->len = string.len;
if(string.str) {
this->str = new char[string.len+1];
strcpy(this->str,string.str);
} else {
this->str = 0;
}
}
operator=:
String & String::operator= (const String& string) {
if(this == & string)
return *this;
delete [] str;
this->len = string.len;
if(string.str) {
this->str = new char[this->len];
strcpy(this->str,string.str);
} else {
this->str = 0;
}
return *this;
}
operator+:
String& operator+(const String& string1 ,const String& string2)
{
String s;
s.len = string1.len + string2.len;
s.str = new char[string1.len + string2.len+1];
strcpy(s.str,string1.str);
strcat(s.str,string2.str);
return s;
}
operator+ should not return a local variable by reference.
Change the return type of operator+ to String. Ie, make the signature:
String operator+( String const& lhs, String const& rhs )
You probably also want to write a "move constructor" for your String class: String( String&& other ) if you are writing your code in C++11.
A simple move constructor:
String::String( String&& other ): len(other.len), str(other.str) {
other.len = 0;
other.str = nullptr;
}
This isn't required, because the copy in the return statement of your operator+ will probably be "elided" by your compiler under non-trivial optimization levels, but still good practice.
It's calling the Destructor because String s is going out of scope in your operator+ overload. Your operator+ overload needs to be returning a copy instead of a reference.
Therefore you should change your operator+ to
String operator+(const String& string1, const String& string2)
Yeah i got your problem
The thing is when you are returning a reference to a temp object from + operator function and then you are assigning this to other object in main So here = overloaded function gets called in to which you are passing a reference to an object that no longer exists
So either you can return a copy from + operator function
or
you can pass a copy in the = overlaoded function