i try to make exercises and have a problem.
I do not know how to overload the operator+ for char;
The aim is to solve those equation:
cout<<"Please enter here a title: "<<endl;
cin>>s2;
s1="I am a " + s2;
The private part of the String class:
private:
char * str; // pointer to string
int len; // length of string
static int num_strings; // number of objects
static const int CINLIM = 80;
i tried the following code, but it doesnt work:
String operator+(const String &st1, const String &st2)
{ String sum;
int len1=std::strlen(st1.str);
int len2=std::strlen(st2.str);
int lenges=len1+len2;
sum.str=new char[lenges+1];
char *a=st1.str;
char *b=st2.str;
while(*a++) {*a++;}
while(*b++) {*a=*b;}
sum.str=st1.str;
return sum.str;
}
Can someone give a tip?
P.S. The class String contains char * str and int len;
Overloaded operators are NOT considered unless at least one operand has a class or enumeration type. In the expression "Hello" + "I am", the operands have types const char[6] and const char[5], which can both decay to const char*, but since only builtin types are involved here, your custom operator+ doesn't do anything.
You will need to explicitly tell the compiler to convert at least one operand to your String type, as in String("Hello") + "I am".
(Or if you want to define a user-defined literal operator, you would be able to write that as something like "Hello"_str + "I am"_str.)
Why dont you try something like this
std::string str = "str1" + std::string("str2");
Related
I am reading about the ""operator and found some weird looking code snip, I did not understand.
I did not understand the conervsion from string "110011" to const char *s, size_t l ?
I was expecting something like:
int operator "" _b (const std::string) { .. } or
int operator "" _b (const char * s) { .. }
userliteral.cpp
...
int operator "" _b (const char * s, size_t l)
{
int decimal {0};
...//conversion
return decimal;
}
main.cpp
int bin2dez01 = "110011"_b; //<--- string "110011" to const char *s, size_t l ??????
std::cout << bin2dez01 << "\n";
operator "" converts a string literal within the program source into another type, in this case an int based on parsing a string representation of a binary number.
The type of a string literal in C++ is const char * - a constant pointer to an array of char representing the contents of the string. You also get a size_t which tells you how long the string is, because you can't tell that just from the pointer.
(The standard for strings in C and C++ is to put a null byte \0 to mark the end of the string, but finding that isn't free, and sometimes they get left out by mistake, so it's always easier to pass the pointer and the length around when you can).
The standard string class std::string can be constructed from a string literal, but unlike in languages like C# and Java they are absolutely not the same type. You get the illusion of it a lot because std::string has various conversion operators and overloads to allow you to work more or less seamlessly with string literals in the ways you'd expect to be able to.
So in summary, there's no conversion going on - the string literal really is a const char *, and the size_t tells you how long it is.
In Lua (apologise, I like working with it the best), the conversion between int and string is done automatically, so
"hi"..2
would result as
"hi2"
In C++ (cause I can't seem to get the default C++11 stoi() and to_string() methods to work) I defined these for myself:
int stoi(string str) {
char* ptr;
strtol(str.c_str(), &ptr, 10);
}
string to_string(int i) {
char* buf;
sprintf(buf, "%d", i);
return buf;
}
which are basically how the default ones are defined anyways.
Then I did this:
string operator+ (string& stuff, int why) {
stuff.append(to_string(why));
}
I tried it on the following code:
void print(string str) {
cout << str << endl;
}
int main() {
cout << stoi("1") + 2 << endl;
print("die" + 1);
return 0;
}
And it outputs
3
ie
Why is this so, and how can I fix it?
EDIT:
Here's what the code looks like now:
using namespace std;
string to_string(int i) {
char* buf;
sprintf(buf, "%d", i);
return buf;
}
string operator+ (string stuff, int why) {
stuff.append(to_string(why));
return stuff;
}
int main() {
cout << string("die") + 2 << endl;
return 0;
}
And it just keeps giving me stackdumps.
Replace print("die" + 1); with cout << std::string("die") + 1;
print() doesn't know what to do with strings. Use std::cout. "die" is a char*, +1 will increment the pointer.
std::string to_string(int i) {
char buf[(sizeof(int)*CHAR_BIT+2)/3+3];
sprintf(buf, "%d", i);
return buf;
}
You need to make an actual buffer to print to. The math is a quick over-estimate of big the largest decimal int is in characters; 3 bits can fit in 1 decimal character, plus null, plus negation, plus rounding, plus 1 for good measure. Hopefully I did not err: do some testing.
Also use snprintf instead of sprintf while you are at it: buffer overflows are not to be toyed with.
The next problem is that "hello" is not a std::string, It is a char const[6] -- an array of 6 char. It can be converted tomstd::string, but +1 will instead convert it to a pointer to the first character, then +1 it to the 2nd character.
Cast it to std::string before.
Finally, it is ambiguous in the standard (really) of pverloading an operator on std::string + int is legal. It is definitely poor practice, as you cannot do it in std legally, and you should overload operators in the type's namespace (so ADL works): these two conflict. On top of that, if std in the future adds such a + your code starts behaving strangely. On top of that, operators are part of a class's interface, and modifying the interface of a class you do not 'own' is rude and a bad habit.
Write your own string class that owns a std::string rather. Or a string view.
Finally, consider telling your compiler to use c++11, you probably just need to pass a flag to it like -std=c++11.
std::string s1("h1");
std::string s2("2");
s1 += s2;
If you are using C++11 compatible compiler you can convert int to string like this:
int i = 2;
std::string s = std::to_string(i);
If you are using Boost library:
#include <boost/lexical_cast.hpp>
int i = 2;
std::string s = boost::lexical_cast<std::string>(i);
Please do not use raw char pointers in C++ for strings.
overloading the operator+ on other than your own types it at best dangerous.
Just use std::to_string in conjunction with operator+ or +=, e.g.
std::string x = "hi";
x += std::to_string(2);
C++14 introduces a user-defined literal that takes a string literal (conversions are applied to make this a pointer) and returns a std::string. In C++11, you can just write your own (this is taken from libstdc++):
inline std::string
operator""_s(const char* str, size_t len)
{
return std::string{str, len};
}
(Note: UDLs without a preceding underscore are reserved names)
And you can use it like this:
// Assumes operator+ is overloaded
print("die"_s + 1);
Demo
"die" is not a std::string. It's a string literal.
Thus when you add 1 to the string literal, it decays to a const char* and the + 1 simply increments that pointer — to next char, 'i'.
Then you call print with the incremented pointer, which causes a std::string to be constructed using that pointer. Since it pointed to the 'i' character, to constructed string is initialized to "ie".
You must first make a std::string out of your string literal to make it call your operator+:
std::cout << std::string("die") + 1;
And then make a few fixes to your operator+:
string operator+ (string stuff, int why) {
return stuff.append(to_string(why));
}
Now it works.
I'm trying to concatenate strings using +, but there is some weird stuff going on. Here is my "Grade" class I have for a class project:
#pragma once
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Grade {
private:
string className;
string student;
string letter;
public:
Grade(string c, string s, string l) : className(c), student(s), letter(l) {}
string getLetterGrade() const { return letter; }
string getClassName() const { return className; }
string getStudent() const { return student; }
void setLetterGrade(string l) { letter = l; return;}
void setClassName(string c) { className = c; return;}
void setStudnet(string s) { student = s; return;}
string toString() const { string output = "hello"+student; return output; }
};
Obviously, the toString() method isn't currently what I want it to be.
If I run the toString() as above, I get "hello529173860" out, as expected. However, if I change the line to:
string toString() const { string output = student+"hello"; return output; }
then the output is "hello3860". This isn't just putting the hello string on the front, but its replacing characters from the student string in the process... somehow?
Furthermore, if I try to use:
string toString() const { string output = "hello"+" world"; return output; }
I get an error:
Grade.h: In member function ‘std::string Grade::toString() const’:
Grade.h:29:53: error: invalid operands of types ‘const char [6]’ and ‘const char [7]’ to binary ‘operator+’
string toString() const { string output = "hello"+" world"; return output; }
^
I'm really at a loss for what it going on here... especially since I have done string concatenation earlier in the program without issue.
What I would like is to output something like:
"student+[some white space]+letter+[some white space]+className"
A std::string can be added to anything (another std::string, double-quoted string literal, char) and provide intuitive results, but if you try to add a double-quoted string literal to another string literal or a char then it won't "work":
a string literal added to a char or other integral value will undergo Standard Conversion to a const char*, then any number added to the pointer will move along the literal that number of characters: if the offset isn't inside the string literal then you get undefined behaviour if you dereference (use) the resultant pointer,
two string literals just can't be added, even after decaying to two pointers, so you'll get a compile-time error.
Sometimes you will want to explicitly construct a std::string so that concatenation with other values works as you'd like: e.g. my_string = std::string("hello ") + my_const_char_ptr + '\n'.
Examples:
std::string s = "Hello";
s + " World"; // ok
"Hello " + s; // ok
"Hello " + "World"; // NOT ok - two string literals
s += " World"; // ok
s += " Goodbye " + "World"; // NOT ok - "+" evaluated before "+="
s += std::string(" Goodbye ") + "World"; // OK - right-hand-side no longer two literals
// BUT may be slower than two "s +="
The constant strings "hello" and "world" are nothing but compile time constants of type const char*. Just like you cannot add two int pointers:
int *p1, *p2;
p1+p1; // Error
You cannot add two (const) char* objects. This is against the C/C++ language rules. If you must concatenate two const-char-pointers, you can just place them together:
"hello" "world"
This technique is mainly useful if you use them along with macros. For example:
// Over simplified
#define ONE(_x) _x
#define TWO(_x) _X
ONE("This is") TWO(" concatenation")
If you are adding two (or more) runtime C-Strings, you must use strXXX functions (like strcat), or better use std::string.
There is no operator + for character arrays. So it is obvious that this code
string toString() const { string output = "hello"+" world"; return output; }
is invalid.
In this expression "hello"+" world" there are used two string literals that have the types correspondingly const char[6] and const char[7]. The operator + is not defined for arrays.
You could just write
string toString() const { return string( "hello" ) + " world"; }
In this case there is used the operator + overloaded for the class std::string. Declaration of the local variable input is redundant. So you could simplify the function even the following way
string toString() const { return "hello world"; }
What is the difference between the line that does not compile and the line that does compile?
The line that does not compile gives this warning: deprecated conversion from string constant to 'char*'
Also, I'm aware casting (char *) on the string being passed in to the function would solve the problem, but I would like to understand why that's even necessary when the 2nd line compiles just fine.
class Student {
public:
Student( char name[] ) {
}
}
int main() {
Student stud( "Kacy" ); //does not compile
char name[20] = "Kacy"; //compiles just fine
}
The char[] signature in the parameter is exactly the same as char*. In C++, it is illegal to convert a string constant char const* (the string "Kacy") to a char* because strings are immutable.
Your second example compiles because the name is an actual array. There is no change to char*.
As a solution, change your parameter to take a const string array:
Student(char const name[]);
which again is the same as
String(char const *name);
though you're better off using std::string:
#include <string>
class String
{
public:
String(std::string name);
};
C++ string literals have type "array of n const char", which decays into const char * in your use case. The implicit conversion to char * (that is, discarding the const) you're trying is deprecated, so there's a warning. Change the type in the constructor's signature or make an explicit const-cast.
From the C++ standard:
An ordinary string literal has type "array of n const char" and static storage duration
The string
"Kacy"
is not an array of characters when the compiler produces the code. Instead, it will stash the string "Kacy" somewhere in memory, and produce a pointer to that place. So what you get is a const char * pointing at the string "Kacy\0".
If you change your constructor to:
Student(const char *nmae)
you can use it both as:
Student stud("Kacy");
and as this:
char name[20] = "Kacy";
Student stud2(name);
Note here that the compiler will generate code to FILL the array name with the characters in "Kacy", which is different from just usinv "Kacy" as an argument to the Student constructor.
EDIT: The code that immediately follows, is the working version, located within the header
inline char * operator & (const char String1 [], const MyStringClass & String2)
{
int length = strlen (String1) + String2.Length();
char * pTemp = new char [length + 1];
strcpy (pTemp, String1);
strcat (pTemp, String2.GetStr());
return pTemp;
}
This is the first time I've felt the need to ask a question, since I've been unable to find helpful information on my own (via search, Google, book, etc). My course book is C++ Primer 5th Edition and I've read Ch. 14 which covers operator overloading. I'm not necessarily looking for an "answer" but rather a nudge in the right direction (because I do want to learn this stuff).
The assignment has us creating our own string class and overloading a bunch of operators that will take a class object on either side - with exception to the assignment operator which may only take a class object on the left side. I've played around with all sorts of return types (this cannot be a member function; efforts to make this a friend function failed).
/*
Note: return by value, otherwise I get a warning of returning the address
of a local variable, temporary. But no matter the return type or what I'm
returning, I always get the error: C2677: binary '&' : no global operator
found which takes type 'MyStringClass' (or there is no acceptable
conversion)
*/
MyStringClass operator & (const char String1 [], const MyStringClass & String2)
{
/*
The only requirement is that the left side has const char [] so that
(const char []) & (MyStringClass &) will concatenate. There is no return
type requirement; so, I could either try and return a string object or
an anonymous C-type string.
cout << StringOject1 << endl; // this works
cout << (StringObject1 & "bacon") << endl; // so does this;
// another function overloads & such that: obj & const char [] works
cout << ("bacon" & StringObject1) << endl; // but not this
*/
MyStringClass S (String1); // initialize a new object with String1
S.Concat (String2); // public member function Concat() concatenates String2
// onto String1 in S
return S; // this does not work
/* a different way of trying this... */
int Characters = strlen (String1) + String2.Length();
int Slots = Characters;
char * pTemp = new char [Slots + 1];
strcpy (pTemp, String1);
strcat (pTemp, String2.pString); // this won't work; pString is a private
// member holding char * and inaccessible
// making it pointless to try and initialize and return an object with pTemp
}
Have looked at your code and from what I can understand, you're probably looking for something like this:
class MyStringClass
{
public:
const char* data() const;
private:
const char* charptr;
};
const char* MyStringClass::data() const
{
return charptr;
}
MyStringClass operator & (const char String1 [], const MyStringClass & String2)
{
/* a different way of trying this... */
int len = strlen(String1) + String2.Length();
char * pTemp = new char [len + 1]; //total length of both strings
strcpy (pTemp, String1);
strcat (pTemp, String2.data()); // you need to have a public member function that returns the string as const char*
MyStringClass str(pTemp); //requires MyStringClass to have constructor that takes char*
return str; //return the string
}