How to overload operator= using const char* and/or string? - c++

I have searched these kind of questions, but I don't still understand why my code has error and how to implement it...
What I want to do is create a class, which can be assigned by string and char* just like std::string...http://www.cplusplus.com/reference/string/string/operator=/
string (1) string& operator= (const string& str);
c-string (2) string& operator= (const char* s);
I can write
string str1 = "haha"; //way(2)
string str2 = str1; //way(1)
So, I write this class...
class LinkedList
{
private:
ListNode *first;
public:
LinkedList():first(nullptr) {};
LinkedList(const string &str);
LinkedList& operator=(const string &str);
LinkedList& operator=(const char *s);
void Print_LinkedList();
void Push_back(char c);
// void Insert();
// void Delete();
// void Invert();
// void Clear();
};
And, the method part is...
LinkedList& LinkedList::operator=(const string &str)
{
if (str.length()%3 != 1)//legal string_input.length is 3n+1
{
cout << "LinkedList building error" << endl;
}
else
{
for (unsigned int i = 0; i < str.length(); i+=3)
{
this->Push_back(str.at(i));
}
}
return *this;
}
LinkedList& LinkedList::operator=(const char *s)
{
// if (???) //please give me some suggestions...
// {
// cout << "LinkedList building error" << endl;
// }
// else
// {
// for (???) //please give me some suggestions...
// {
// this->Push_back(???); //please give me some suggestions...
// }
// }
this->Push_back('x');
return *this;
}
And, the main part is...
int main()
{
LinkedList linkedlist1;
linkedlist1.Push_back('x');
linkedlist1.Push_back('a');
linkedlist1.Print_LinkedList();
string str_test = "H->a";
LinkedList linkedlist2(str_test);
linkedlist2.Print_LinkedList();
string str_test2 = "H->A->h->o";
LinkedList linkedlist3 = str_test2;
linkedlist3.Print_LinkedList();
LinkedList linkedlist4 = "x"; //there's an error in this line
linkedlist4.Print_LinkedList();
return 0;
}
Then, the compiler says,
"error: conversion from 'const char [2]' to non-scalar type 'LinkedList' requested|"
Could you tell me...
1.why dose my code have the compiler error?
2.how can I fix the bug?
3.some suggestions for implementing in the "LinkedList& LinkedList::operator=(const char *s){//how should I write here}"
Thanks for your help.

Related

No suitable constructor exists to convert from const char to "custom string", though I have created one

I am doing a custom string class in C++. However, when I debugged my code, the system said that:
Error E0415:no suitable constructor exists to convert from "const char" to "string"
Here is my header file where my custom string class is defined:
#ifndef _STRING
#define _STRING
#include <iostream>
class string {
private:
char* s = nullptr;
unsigned int size = 0;
public:
string();
~string() { delete s; };
void operator=(const char*);
friend std::ostream& operator<<(std::ostream&, string&);
};
#endif
string::string()
: s{ nullptr }
{
s = new char[1];
s[0] = '\0';
}
void string::operator=(const char* source)
{
if (source == nullptr) {
s = new char[1];
s[0] = '\0';
}
else {
size = strlen(source) + 1;
s = new char[size];
for (int k = 1; k < (strlen(source) + 1); k++) {
s[k] = source[k];
}
}
}
std::ostream& operator<<(std::ostream& output, string& result)
{
output << result.s;
return output;
}
And here is my main file which I tried to comply:
#include "custom_string.h"
int main()
{
string a;
a = "testfile";
std::cout << a;
system("pause");
return 1;
}
As you can see, I have declared a constructor to convert const char to my custom string by overloading assignment operator. However, there should be something wrong in my code and I could not find out it. Please help me and thank you
Thanks everyone, I have done to fix it. As it turned out, I have to declare one more constructor to covert between my custom string and const char. That is something like this:
string::string(const string& t){}
string& string::operator=(const char&source){}

Is this approach change the object of the name only?

I want Swap the name (i.e. string in cName[]) of the two cats using the pointer approach.
However I want to Only swap the name, NOT the object.
Am I correct?
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;
class CAT
{
public:
CAT(char * firstname) { strncpy(cName, firstname, 79); }
~CAT() { ; }
char * getName() { return cName; }
void setName(char *nameinput) { strncpy(cName, nameinput, 79); }
private:
char cName[80];
};
void nameSwap(CAT *CatA, CAT *CatB)
{
char testing[] = "testing";
CAT temp =CAT(testing);
temp = *CatA;
*CatA = *CatB;
*CatB = temp;
}
int main()
{
char Taby[] = "Taby";
char Felix[] = "Felix";
CAT pA = CAT(Taby);
CAT pB = CAT(Felix);
cout << "The inital name pA is " << pA.getName() << " and pA is" << pB.getName() << endl;
nameSwap(&pA, &pB);
cout << "After approach" << endl;
cout << "The name pA is " << pA.getName() << " and " << pB.getName() << endl;
system("PAUSE");
return 0;
}
You are actually swapping the whole objects, not only the name of the CAT.
If you only want to swap the name, you need to access the cName member in a similar way as you are doing for the objects. You'd also need permission to access to the cName member in such a swap function, which a function outside won't have since cName is private. Make the swap function a member of your class:
class CAT
{
public:
CAT(const char* firstname) { strncpy(cName, firstname, 80); }
~CAT() {}
const char* getName() const { return cName; }
void setName(const char *nameinput) { strncpy(cName, nameinput, 80); }
void swapName(CAT& CatB)
{
char tmp[80];
strncpy(tmp, CatB.cName, 80);
strncpy(CatB.cName, cName, 80);
strncpy(cName, tmp, 80);
}
private:
char cName[80];
// other CAT attributes won't be affected by the name swap
};
And call it like this
pA.swapName(pB); // or pB.swapName(pA); - same result
But consider using std::string instead of char[]. You'll soon find C++ strings much easier to work with and also, when swapping those, only the pointers to the underlying memory is swapped, so it's more effective.
std::string one;
std::string two;
one.swap(two);
Edit: As per request, I added a version using pointers.
I made it in a haste and haven't debugged it so I've probably made a lot of mistakes. First, I made a new class called wong_string that will hold the name and any other attributes suiteable for strings.
#include <stdexcept>
#include <cstring>
class wong_string {
char* m_data;
static char* duplicate(const char* str) {
size_t len = std::strlen(str)+1;
char* rv = new char[len];
std::memcpy(rv, str, len);
return rv;
}
public:
// default constructor: wong_string howdy1;
wong_string() : m_data(nullptr) {}
// conversion constructor: wong_string howdy2("value2");
wong_string(const char* cstr) :
m_data(duplicate(cstr))
{}
// copy constructor: wong_string howdy3 = howdy2;
wong_string(const wong_string& rhs) : wong_string(rhs.m_data) {}
// move constructor: wong_string howdy4 = wong_string("value4");
wong_string(wong_string&& rhs) : m_data(rhs.m_data) {
rhs.m_data = nullptr;
}
// copy assignment operator: (wong_string howdy5;) howdy5 = howdy4;
wong_string& operator=(const wong_string& rhs) {
if(this!=&rhs) {
char* tmp = duplicate(rhs.m_data);
if(m_data) delete []m_data;
m_data = tmp;
}
return *this;
}
// copy assignment operator from c string
wong_string& operator=(const char* rhs) {
*this = wong_string(rhs);
return *this;
}
// move assignment operator: (wong_string howdy6;) howdy6 = wong_string("value6");
wong_string& operator=(wong_string&& rhs) {
if(this!=&rhs) {
m_data = rhs.m_data;
rhs.m_data = nullptr;
}
return *this;
}
// destructor, free memory allocated by duplicate(), if any
~wong_string() {
if(m_data) delete []m_data;
}
// comparisons
bool operator==(const wong_string& rhs) const {
return strcmp(m_data, rhs.m_data)==0;
}
bool operator!=(const wong_string& rhs) const {
return !(*this==rhs);
}
// conversion to a normal c string
operator char const* () const { return m_data; }
// output stream operator
friend std::ostream& operator<<(std::ostream&, const wong_string&);
// input stream operator - not implemented yet
};
with that in place, your CAT can be made into something like this:
class CAT
{
public:
CAT(const char* firstname, const char* nickname=nullptr) :
cName(firstname),
cNickName(nickname?nickname:firstname)
{}
~CAT() {}
const char* getName() const { return cName; }
void setName(const char *nameinput) { cName=nameinput; }
void swapName(CAT& CatB)
{
std::swap(cName, CatB.cName);
}
private:
wong_string cName; // Madame Florence Jenkins III
// other CAT attributes won't be affected by the name swap
wong_string cNickName; // Ms. Miao
};
So, there you have it. Pointers galore...

No instance of overloaded function matches argument list.

I'm working on a project for class, but keep getting the error: no instance of overloaded function matches argument list. It is referencing my String classes. What I am trying to do is create a Copy, Concat and Count functions with out using the string class. Any help would be greatly appreciated.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
class String
{
private:
char str[100];
char cpy[100];
public:
static const char NULLCHAR = '\0';
String()
{
str[0] = NULLCHAR;
cpy[0] = NULLCHAR;
}
String(char* orig, char* cpy)
{
Copy(orig, cpy);
}
void Display()
{
cout << str << endl;
}
void Copy(char* orig, char* dest)
{
while (*orig != '\0') {
*dest++ = *orig++;
}
*dest = '\0';
}
void Copy(String& orig, String& dest)
{
Copy(orig.str, dest.cpy);
}
void Concat(char* orig, char* cpy)
{
while (*orig)
orig++;
while (*cpy)
{
*orig = *cpy;
cpy++;
orig++;
}
*orig = '\0';
}
void Concat(String& orig, String& cpy)
{
Concat(orig.str, cpy.cpy);
}
int Length(char* orig)
{
int c = 0;
while (*orig != '\0')
{
c++;
*orig++;
}
printf("Length of string is=%d\n", c);
return(c);
}
};
int main()
{
String s;
s.Copy("Hello");
s.Display();
s.Concat(" there");
s.Display();
String s1 = "Howdy";
String s2 = " there";
String s3;
String s4("This String built by constructor");
s3.Copy(s1);
s3.Display();
s3.Concat(s2);
s3.Display();
s4.Display();
system("pause");
return 0;
}
It looks like your Copy and Concat functions each take two parameters, yet you pass them both a single parameter. If you want to copy them into a String object, your code should look more like:
String Copy(char* orig)
{
// Same copy logic you have,
// except copy into "*this"
}
As the error message says, There is no version of the constructor for your String class that takes a single parameter. You have a default constructor and one that takes two parameters.
You need to define one which takes a single parameter and initializes the str
String s4("This String built by constructor");
this statement needs construction function
String(char *);

C++ ostream output wrong [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I have a problem and I can't solve it.
note: I can't use any string/strlen/strcmp and such functions
My problem is when I'm trying to print obj after cin, when I don't put him value it prints garbage, and if I put value it change it by cin it print it well.
#ifndef __STRING_H__
#define __STRING_H__
#include <iostream>
using namespace std;
class String {
private:
char* Str; //pointer to string
int Str_s; // size of string public:
String(char* str = NULL);
~String();
void const print() const; //check
//~~~~~~~~~~~~~~~~~~
// operators
//~~~~~~~~~~~~~~~~~
String& operator=(const String& str);
bool operator==(const String& s) const;
bool operator!=(const String& s) const;
void operator-=(const char c);
void operator+=(const char c);
char& operator[](const int index) const;
//~~~~~~~~~~~~~~~~~~
// i/o ~~ operators
//~~~~~~~~~~~~~~~~~
friend ostream& operator<<(ostream&, const String& s);
friend istream& operator>>(istream&, String& s);
//~~~~~~~~~~~~~~~~~~
// arrange method
//~~~~~~~~~~~~~~~~~
void Letters(); // arrange all letter in sentence
void Space(); //remove all unwanted spaces
void Set_Str_s(int num) {
this->Str_s = num;
}
int Get_Str_s() {
return this->Str_s;
}
//~~~~~~~~~~~~~~~~~~
// methods
//~~~~~~~~~~~~~~~~~
char const* STR() {
return Str;
}
};
#endif
ostream& operator<<(ostream& output, const String& s) {
//char *c = s.Str;
//output << c << endl;
for (int i = 0; i < s.Str_s; i++) {
cout << s.Str[i];
}
return output;
}
istream& operator>>(istream& input, String& s) {
if (s.Str == NULL) {
s.Str_s = 0;
char temp[BUFFER];
int i = 0, j = 0;
cin.getline(temp, BUFFER);
while (temp[i] != NULL) {
s.Str_s++;
i++;
}
//s.Str = new char[s.Str_s];
s.Str = temp;
} else {
input >> s.Str;
}
return input;
}
#include <iostream>
using namespace std;
#include "string_head.h"
#include "Definition_head.h"
#include "Menu_head.h"
int main() {
char* c = "hi";
char* h = "lilo";
String s, m(c);
cin >> s;
cin >> m;
cout << s;
cout << endl;
cout << m;
}
The following line is a problem:
s.Str = temp;
you are storing a pointer to a local array that will be deleted when the function returns. Use something like:
s.Str = strdup(temp);
If your platform doesn't support strdup, you can implement it. It's not too hard.
The following line is also a problem:
input >> s.Str;
If there isn't enough memory to hold the string being read, you will be writing into memory that you are not supposed to.

Segmentation fault: 11 and malloc errors in C++ code

Ok, so I know there are probably a lot of errors in this code. I'm pretty new to dynamic memory allocation, pointers, etc.
The header file, account.h, is given to us by our professor. We were told not to make any changes to the .h file.
The implementation file is written by me. The main function is included just for basic initial testing. We were given another file to actually test the implementation of the account class.
If I don't comment out the cout name line, I get a seg fault 11 error.
If I do, it'll print the account number, but throw this error:
Test(29976) malloc: * error for object 0x62c1aa18c9d8374: pointer being freed was not allocated* set a breakpoint in malloc_error_break to debug
Abort trap: 6
Any help at all would be greatly appreciated!
Here's the header file:
class account
{
public:
typedef char* string;
static const size_t MAX_NAME_SIZE = 15;
// CONSTRUCTOR
account (char* i_name, size_t i_acnum, size_t i_hsize);
account (const account& ac);
// DESTRUCTOR
~account ( );
// MODIFICATION MEMBER FUNCTIONS
void set_name(char* new_name);
void set_account_number(size_t new_acnum);
void set_balance(double new_balance);
void add_history(char* new_history);
// CONSTANT MEMBER FUNCTIONS
char* get_name ( ) const;
size_t get_account_number ( ) const;
double get_balance( ) const;
size_t get_max_history_size( ) const;
size_t get_current_history_size ( ) const;
string* get_history( ) const;
friend ostream& operator <<(ostream& outs, const account& target);
private:
char name[MAX_NAME_SIZE+1]; //name of the account holder
size_t ac_number; //account number
double balance; //current account balance
string *history; //Array to store history of transactions
size_t history_size; //Maximum size of transaction history
size_t history_count; //Current size of transaction history
};
Here is the implementation file:
// File: account.cxx
// Author: Mike Travis
// Last Modified: Mar 3, 2012
// Description: implementation of Account class as prescribed by the file account.h
#include <cstdlib>
#include <stdio.h>
#include <iostream>
#include "account.h"
using namespace std;
//Constructor
account::account(char* i_name, size_t i_acnum, size_t i_hsize){
string *d_history;
d_history = new string[i_hsize];
for(int i = 0; i<i_hsize; i++){
name[i] = i_name[i];
}
ac_number = i_acnum;
history_size = i_hsize;
history_count = 0;
}
account::account(const account& ac){
string *d_history;
d_history = new string[ac.history_size];
for( int i=0; i<ac.get_current_history_size(); i++){
strcpy(d_history[i], history[i]);
}
strcpy(name,ac.get_name());
ac_number = ac.get_account_number();
history_size = ac.get_max_history_size();
history_count = ac.get_current_history_size();
}
account::~account(){ delete [] history; }
void account::set_name(char* new_name){ strcpy(name, new_name); }
void account::set_account_number(size_t new_acnum){ ac_number = new_acnum; }
void account::set_balance(double new_balance){ balance = new_balance; }
void account::add_history(char* new_history){
strcpy(history[history_count], new_history);
history_count++;
}
char* account::get_name() const {
char* name_cpy;
strcpy(name_cpy, name);
return name_cpy;
}
size_t account::get_account_number() const{ return ac_number; }
double account::get_balance() const{ return balance; }
size_t account::get_max_history_size() const{ return history_size; }
size_t account::get_current_history_size() const{ return history_count; }
//string* account::get_history() const{ return *history; }
int main(){
account test1("mike travis", 12345, 20);
//cout<<"\nname: "<< test1.get_name();
cout<<"\n\nacnum: "<<test1.get_account_number()<<"\n\n";
return 0;
}
In the destructor of account, you delete the history array. However, in the constructor, you allocate (and leak) an array which is stored in the local variable d_history. You presumably wanted to assign that to the member variable history instead - since you haven't, if you get to the destructor it gives you an error saying that you're freeing history but have never allocated it.
There's a similar error in the copy constructor as well.
There are also other errors in your code as well, which I assume you'll find as you go - get_name(), for example, is not going to work. I suspect the header file is not helping here, but there's not much to be done if you're not supposed to change that.
I've written a little bit code for you and corrected the epic mistakes (even in the header file, sorry ;)). It is still extremely ugly and c-ish, but maybe you can learn something reading it:
#include <cstddef>
#include <ostream>
class account
{
// The whole class makes no sense, since it has no useful
// member function or anything like this.
// Furthermore, the class provides almost full access to all its member variables.
// At this point one could just make everything public.
// This is not even exception safe when the constructor throws.
// A good implementation would use history_entry and history classes,
// together with std::string and std::vector/std::deque
// And it would provide some sort of functionality. ;)
public:
account(const char* name, unsigned number, std::size_t history_max_size);
account(const account& other);
~account();
const char* name() const;
unsigned number() const;
double balance() const;
const char* const* history() const;
std::size_t history_size() const;
unsigned history_max_size() const;
void set_name(const char* new_name);
void set_number(unsigned new_number);
void set_balance(double new_balance);
void add_history(const char* new_history);
private:
char* name_;
unsigned number_;
double balance_;
char** history_;
std::size_t history_size_;
const std::size_t history_max_size_;
};
std::ostream& operator << (std::ostream& stream, const account& a);
#include <cassert>
#include <cstring>
account::account(const char* name, unsigned number, std::size_t history_max_size)
: name_(0)
, number_(number)
, balance_(0.0)
, history_(new char*[history_max_size])
, history_size_(0)
, history_max_size_(history_max_size)
{
assert(name != 0);
assert(history_max_size != 0);
set_name(name);
}
account::account(const account& other)
: name_(0)
, number_(other.number_)
, balance_(other.balance_)
, history_(new char*[other.history_max_size_])
, history_size_(other.history_size_)
, history_max_size_(other.history_max_size_)
{
set_name(other.name_);
for (std::size_t i = 0; i != other.history_size_; ++i)
{
history_[i] = new char[std::strlen(other.history_[i]) + 1];
strcpy(history_[i], other.history_[i]);
}
}
account::~account()
{
delete[] name_;
for (std::size_t i = 0; i != history_size_; ++i)
delete[] history_[i];
delete[] history_;
}
const char* account::name() const
{
return name_;
}
unsigned account::number() const
{
return number_;
}
double account::balance() const
{
return balance_;
}
const char* const* account::history() const
{
return history_;
}
std::size_t account::history_size() const
{
return history_size_;
}
unsigned account::history_max_size() const
{
return history_max_size_;
}
void account::set_name(const char* new_name)
{
if (name_)
delete[] name_;
name_ = new char[std::strlen(new_name) + 1];
std::strcpy(name_, new_name);
}
void account::set_number(unsigned new_number)
{
number_ = new_number;
}
void account::set_balance(double new_balance)
{
balance_ = new_balance;
}
void account::add_history(const char* new_history)
{
if (history_size_ == history_max_size_)
{
delete[] history_[0]; // delete oldest entry
for (std::size_t i = 0; i != history_size_ - 1; ++i)
history_[i] = history_[i + 1];
--history_size_;
}
history_[history_size_] = new char[strlen(new_history) + 1];
std::strcpy(history_[history_size_], new_history);
++history_size_;
}
std::ostream& operator << (std::ostream& stream, const account& a)
{
return stream << "account [name: " << a.name() << ", number: "
<< a.number() << ", balance: " << a.balance() << ']';
}
#include <iostream>
int main()
{
account a("Hello!", 500, 5);
a.set_balance(12.546);
for (int i = 50; i--; )
a.add_history("Yaaay..");
//account b = a;
std::cout << a << '\n';
}