I'm having some issues compiling the code I wrote which has a custom class with an overloaded =.
rnumber.hpp:
#include <string>
class rnumber {
public:
std::string number;
// I added this constructor in an edit
rnumber(std::string s) { number = s; }
void operator=(std::string s) { number = s; }
bool operator==(std::string s) { return number == s; }
friend std::ostream &operator<<(std::ostream &os, const rnumber n);
};
std::ostream &operator<<(std::ostream &os, const rnumber n) {
os << n.number;
return os;
}
main.cpp:
#include "rnumber.hpp"
#include <iostream>
#include <string>
int main() {
rnumber a = "123";
}
For some reason, this does not compile with the error conversion from ‘const char [4]’ to non-scalar type ‘rnumber’ requested. This shouldn't be a problem, because rnumber has an overload for =. Why am I getting this error?
EDIT: Even after adding a constructor, it doesn't work.
rnumber a = "123"; tries to initialize a with a const char*, but there is no constructor taking a const char*.
You need to implement this constructor as well:
rnumber(const char *s) { number = s; }
There are other possibilities, mentioned on other answer and comments.
The problem is that rnumber a = "123"; is initialization and not assignment so that the copy assignment operator= cannot be used.
There are 2 ways to solve this as shown below:
Method 1
Use the converting constructor rnumber::rnumber(std::string)
int main() {
rnumber a("123"); //this uses the converting ctor
}
Method 2
Create the object and then do the assignment:
int main() {
rnumber a("somestring"); //creates the object using converting ctor
a = "123"; //uses assignment operator
}
"abc" is not a std::string literal, it is a string literal, in particular it is a const char[4]. There is an implicit conversion from const char[4] to std::string, by one of it's constructors, and an implicit conversion from std::string to rnumber by the constructor you edited in, but you only get one implicit constructor per initialisation.
What you can do is explicitly construct the rnumber, and the std::string parameter can be implicitly constructed.
int main() {
rnumber a { "123" };
}
The problem's that I was using the wrong constructor.
rnumber(std::string s) { number = s; } is an std::string constructor, where the assignment rnumber a = "123"; is assigning a const char* to a.
Add another constructor rnumber(const char *s) { number = s; } to the header.
Related
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;
Assuming I have two classes which are not related by inheritance. e.g:
class MyString
{
private:
std::string str;
};
class MyInt
{
private:
int num;
};
and I want to be able to convert one to another using regular casting e.g MyInt a = (MyInt)mystring (where mystring is of class MyString).
How does one accomplish such a thing?
The conversion needs to make sense first of all. Assuming it does, you can implement your own conversion operators, like in the example below:
#include <string>
#include <iostream>
class MyInt; // forward declaration
class MyString
{
std::string str;
public:
MyString(const std::string& s): str(s){}
/*explicit*/ operator MyInt () const; // conversion operator
friend std::ostream& operator<<(std::ostream& os, const MyString& rhs)
{
return os << rhs.str;
}
};
class MyInt
{
int num;
public:
MyInt(int n): num(n){}
/*explicit*/ operator MyString() const{return std::to_string(num);} // conversion operator
friend std::ostream& operator<<(std::ostream& os, const MyInt& rhs)
{
return os << rhs.num;
}
};
// need the definition after MyInt is a complete type
MyString::operator MyInt () const{return std::stoi(str);} // need C++11 for std::stoi
int main()
{
MyString s{"123"};
MyInt i{42};
MyInt i1 = s; // conversion MyString->MyInt
MyString s1 = i; // conversion MyInt->MyString
std::cout << i1 << std::endl;
std::cout << s1 << std::endl;
}
Live on Coliru
If you mark the conversion operators as explicit, which is preferable (need C++11 or later), then you need to explicitly cast, otherwise the compiler will spit an error, like
MyString s1 = static_cast<MyString>(i1); // explicit cast
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.
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
I'm writing a String class. I'd like to be able to assign my strings such as;
a = "foo";
printf(a);
a = "123";
printf(a);
int n = a; // notice str -> int conversion
a = 456; // notice int -> str conversion
printf(a);
I've already assigned my operator=() method for string to integer conversion. How can I declare another operator=() so that I can do the reverse method?
When I declare another, it seems to override the previous.
String::operator const char *() {
return cpStringBuffer;
}
String::operator const int() {
return atoi(cpStringBuffer);
}
void String::operator=(const char* s) {
ResizeBuffer(strlen(s));
strcpy(cpStringBuffer, s);
}
bool String::operator==(const char* s) {
return (strcmp(cpStringBuffer, s) != 0);
}
//void String::operator=(int n) {
// char _cBuffer[33];
// char* s = itoa(n, _cBuffer, 10);
// ResizeBuffer(strlen(_cBuffer));
// strcpy(cpStringBuffer, _cBuffer);
//}
A single-argument constructor can act as an int->String conversion, whereas a so-called conversion operator does the converse int->String
class String
{
public:
String(int) {} // initialization of String with int
String& operator=(int) {} // assignment of int to String
operator int() const {} // String to int
};
Note however, that these conversions will happen implicitly and you can easily get bitten. Suppose you would extend this class to also accept std::string arguments and conversions
class String
{
public:
String(int) {} // int to String
String(std::string) {} // std::string to String
// plus two assignment operators
operator int() const {} // String to int
operator std::string const {} // String to std::string
};
and you would have these two function overloads
void fun(int) { // bla }
void fun(std::string) { // bla }
Now try and call fun(String()). You get a compile error because there are multiple -equally viable- implicit conversions. THat's why C++98 allows the keyword explicit in front of single-argument constructors, and C++11 extends that to explicit conversion operators.
So you would write:
class String
{
public:
explicit String(int) {} // int to String
explicit operator int() const {} // String to int
};
One example where implicit conversion might be legitate is for smart pointer classes that want to convert to bool or (if they are templated) from smart_pointer<Derived> to smart_pointer<Base>.
Rather than assignment operators, you probably want conversion
operators—there's no way you can define an additional assignment
operator for int. In your String class, you might write:
class String
{
// ...
public:
String( int i ); // Converting constructor: int->String
operator int() const; // conversion operator: String->int
// ...
};
You can add assignment operators in addition to the first, but they
generally aren't necessary except for optimization reasons.
And finally, I think you'll find this a bad idea. It's good if the goal
is obfuscation, but otherwise, implicit conversions tend to make the
code less readable, and should be avoided except in obvious cases (e.g.
a Complex class should have a converting constructor from double).
Also, too many implicit conversions will result in ambiguities in
overload resolution.
To convert your class to the other you need conversion operator. Something like this:
struct Foo
{
operator int() const //Foo to int
{
return 10;
}
operator=(int val) //assign int to Foo
{
}
operator=(const std::string &s) //assign std::string to Foo
{
}
};
To enable int n = a (where a is an object of your string class) you need a conversion operator.
class string {
public:
operator int() const { return 23; }
};
To enable conversion to your type, you need a converting assignment and possibly a conversion constructor.
class string {
public:
string(int i);
string& operator=(int i);
};
You will also need overloads for const char*, char* and so on.