I've created simple string class with some extra functions - its mainly for learning purposes.
Now i want to overload operator + to allow me add two or more char* to my string.
this is what i want to make:
tom::string TXT;
TXT="abcde" + "1234";
cout << TXT << endl;
and output have to be:
abcde1234
i want to add more than just const char* later like:
..
int NUM=34;
TXT="abcd"+NUM+"098";
cout << TXT << endl;
and output have to be:
abcd34098
ive already done similar thing with operator <<
TXT << "abcd" << ".......";
but i need it with + operator.
another thing is (probably it will be sorted with + operator)
void testF(tom::string INP) {
cout << INP << endl;
}
int NUM=123;
testF("abcd"+NUM+"efg");
with output:
abcd123efg
if i'm trying anything still ending with error:
error: invalid operands of types
‘const char [4]’ and ‘const char [3]’
to binary ‘operator+’
here is part of the tom::string class:
namespace tom {
class string {
private:
unsigned int _length;
unsigned int _search_pos;
bool _changed;
bool _indexed;
char* _buffer;
unsigned int* _indexes;
unsigned int _indexCount;
char* _emptyChar;
unsigned int _null;
char* _retBuffer[RET_BUFFERS];
short unsigned int _retBufferIndex;
// ADD to string
void _add (const char* txt) {
_buffer=(char*) realloc(_buffer, sizeof(char)*(_length+strlen(txt)+1));
memcpy(&_buffer[_length], txt, strlen(txt));
_length=_length+strlen(txt);
_buffer[_length]=static_cast<char>(0);
_changed=true;
free(_indexes);
_changed=true;
_indexCount=0;
_indexed=false;
_indexes = (unsigned int*) malloc (sizeof(unsigned int)*2);
}
// .......
// REPLACE Whole string
string& _rvs(const char* txt) {
free(_buffer);
free(_indexes);
_changed=true;
_indexCount=0;
_indexed=false;
_indexes = (unsigned int*) malloc (sizeof(unsigned int)*2);
_length=strlen(txt);
_buffer = (char*) malloc (sizeof(char)*(_length+1));
memcpy(_buffer, txt, _length);
_buffer[_length]=static_cast<char>(0);
return (*this);
}
// .......
public:
// ----------------------------------------------
// | CONSTRUCTOR |
// ----------------------------------------------
string(const char* _init="") {
_length=0;
_indexCount=0;
_changed=false;
_indexed=false;
_buffer = (char*) malloc (sizeof(char)*(strlen(_init)+1));
memcpy(_buffer, _init, strlen(_init));
_indexes = (unsigned int*) malloc (sizeof(unsigned int)*2);
_emptyChar = (char*) malloc (sizeof(char));
_buffer[strlen(_init)]=static_cast<char>(0);
_emptyChar[0]=static_cast<char>(0);
_null=(unsigned int)-1;
_retBufferIndex=0;
for (short unsigned int ii=0; ii<RET_BUFFERS; ii++) {
_retBuffer[ii] = (char*) malloc (sizeof(char));
_retBuffer[ii][0]=static_cast<char>(0);
}
}
string(const tom::string& _init) {
string((const char*)_init.c_str());
}
// ----------------------------------------------
// | DESTRUCTOR |
// ----------------------------------------------
~string() {
free(_buffer);
free(_indexes);
free(_emptyChar);
for (short unsigned int ii=0; ii<RET_BUFFERS; ii++) {
free(_retBuffer[ii]);
}
}
// .....
string& operator = (string &ttxt) {
const char* txt=ttxt.c_str();
return (_rvs(txt));
}
string& operator = (const char* txt) {
return (_rvs(txt));
}
string& operator = (int num) {
char bf[32];
sprintf (bf, "%d", num);
const char* txt=bf;
return (_rvs(txt));
}
string& operator << (const char* txt) {
_add(txt);
return(*this);
}
string& operator << (int num) {
char bf[32];
sprintf (bf, "%d", num);
const char* txt=bf;
_add(txt);
return(*this);
}
operator const char*() {
return (const char*)_buffer;
}
// .....
}
}
You can't overload operators for pointer types only. At least one of the involved types needs to be a user-defined type.
tom::string TXT;
TXT="abcde" + "1234";
cout << TXT << endl;
"abcde" + "1234" is evaluated first - you cannot make it work like you want.
You can make e.g. this work though:
tom::string TXT;
TXT=tom::string("abcde") + 987 + "1234";
cout << TXT << endl;
That will require an operator+(int) and an operator+(char const *)
EDIT: Sample operator:
operator+ should return a new object - not modify the object it is called on.
class string {
...
friend string operator+(string const & LHS, char const * RHS) {
string s = LHS;
s._add(RHS);
return s;
}
};
Thanx to Erik! ... sorted (working)
i've added to tom::string class:
friend string operator+(string const & LHS, char const * RHS) {
string s;
s=LHS;
s._add(RHS);
return s;
}
next one throwing malloc error - i have to check it, but the first working perfect!
friend string operator+(string const & LHS, char const * RHS) {
string s=LHS;
s._add(RHS);
return s;
}
and the testing:
void test2 (tom::string ooo) {
cout << ooo << endl;
}
test2(tom::string("abcde")+"AA"+"BB");
showing:
abcdeAABB
Thanx again!
Related
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){}
I am trying to write a C++ program that has a class Student. I am trying to make a getter for the name attribute, but I am getting this error:
\ApplicationFile.cpp:95:9: error: no match for 'operator*' (operand type is 'const string' {aka 'const std::__cxx11::basic_string'})
return *name;
Any ideas why?
This is what I have done so far:
#include <iostream>
#include <string.h>
#include <string>
#include <stdio.h>
using namespace std;
class Student
{
char *AM;
string name;
int semester, lessons;
float *passed;
public:
Student (const char *am, string n); //Constructor that I give only the serial number (AM) and the name
Student (const char *am, string n, int semester); //Constructor that I give only the serial number (AM), the name and the semester
Student (const char *am, string n, int semester, int lessons, float * passed); //Constructor that I give values to all the attributes
Student (Student &x);
void setAm (const char *am); //Set serial number
char * getAm () const; //Get serial number
void setName (string n); //Set name
string * getName () const; //Get name
};
//Only AM and Name
Student::Student(const char *am, string n)
{
int l = strlen (am);
AM = new char [l + 1];
strcpy (AM, am);
name = n;
semester = 1;
lessons = 0;
*passed = {0};
}
//Only serial number (am), name (n), semester (e)
Student::Student(const char * am, string n, int e)
{
int l = strlen (am);
AM = new char [l + 1];
strcpy (AM, am);
name = n;
semester = e;
lessons = 0;
*passed = {0};
}
//Constructor that we give values to all variables
Student::Student(const char * am, string n, int e, int perasm, float *p)
{
int l = strlen (am), i;
AM = new char [l + 1];
strcpy (AM, am);
name = n;
semester = e;
lessons = perasm;
*passed = *p;
}
void Student::setAm(const char *am)
{
delete [] AM;
int l = strlen(am);
AM = new char[l + 1];
strcpy (AM, am);
}
char * Student::getAm() const
{
return AM;
}
void Student::setName (const string s)
{
name = s;
}
string * Student::getName () const
{
return *name;
//return c;
}
int main()
{
Student Kostas("123", "Kostas");
cout << Kostas.getAm() <<endl;
Kostas.setAm("354");
cout << Kostas.getAm() <<endl;
float p[] = {5.1, 4.4, 0.0, 0.0, 0.0};
Student Giwrgos("678", "Giwrgos", 6, 5, p);
cout << Giwrgos.getName();
return 0;
}
As the error states there is no mach for operator *, the operand type is const string, the operation does not make sense, you are trying to dereference a non-pointer variable and return it as a pointer.
You can return a pointer if you return the address of name:
const string *Student::getName () const
{
return &name;
}
You can/should return a reference:
const string& Student::getName () const
{
return name;
}
The name member is declared as a string object, not a string* pointer to a string object. Your getName() method is declared to return a string* pointer, but it is trying to use the * operator to turn the name object into a pointer, which will not work. std::string does not have such an operator* implemented, which is why you are getting the compiler error. But, more importantly, the * operator is simply the wrong operator to use to make a pointer to name. You need to use the & address operator instead.
However, since getName() is declared as const, its implicit this pointer is const, and thus it accesses the name as a const object. You cannot return a pointer-to-non-const that points to a const object (without using const_cast, which you should avoid).
There is no good reason for a non-mutating getter to return a poiner-to-non-const that is pointing at internal data. It should return a pointer-to-const instead, eg:
const string* Student::getName () const;
// or: string const * Student::getName () const;
...
const string* Student::getName () const
// or: string const * Student::getName () const
{
return &name;
}
And then, you need to dereference that pointer when you are passing the string to std::cout, eg:
cout << *(Giwrgos.getName());
However, since the pointer can never be null, it would be better to return the name object by reference-to-const instead of by pointer-to-const:
const string& Student::getName () const;
// or: string const & Student::getName () const;
...
const string& Student::getName () const
// or: string const & Student::getName () const
{
return name;
}
...
cout << Giwrgos.getName();
Or, you can return the name object by value instead (which will return a copy of the string data):
string Student::getName () const;
...
string Student::getName () const
{
return name;
}
...
cout << Giwrgos.getName();
In the Student class, change
string * getName () const; //Get name
to
string * getName (); //Get name
and then change:
string * Student::getName () const
{
return *name;
//return c;
}
to:
string * Student::getName ()
{
return &name;
//return c;
}
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...
#include <iostream>
#include <string>
using namespace std;
class String {
public:
String();
String(const char []);
String(const String &);
int Compare(const String &) const;
int Compare(const char[]) const;
String & Copy(const String &);
String & Copy(const char[]);
size_t Len() const;
String & Conc(const char[]);
String & Conc(const String &);
String Display() const;
private:
size_t Letters;
size_t Slots;
char* Fazah;
};
String::String() {
Letters = 0;
Slots = Letters;
Fazah = new char [Slots + 1];
Fazah[0]= '\0';
}
String::String(const char otherVar[]) {
Letters = strlen(otherVar);
Slots = Letters;
Fazah = new char [Slots + 1];
strcpy(Fazah, otherVar);
}
String::String(const String & otherVar) {
Slots = otherVar.Slots;
Letters = otherVar.Letters;
Fazah = new char [Slots + 1];
strcpy (Fazah, otherVar.Fazah);
cout <<"Copy const"<< endl;
}
int String::Compare (const String & otherVar) const {
return strcmp (Fazah, otherVar.Fazah);
}
int String::Compare(const char otherVar []) const {
return strcmp (Fazah, otherVar);
}
inline size_t String::Len ()const {
return Letters;
}
String String::Display() const {
return* this;
}
String & String::Copy(const String & otherVar) {
delete[] Fazah;
Letters = otherVar.Letters;
Slots = otherVar.Letters;
Fazah = new char [Slots + 1];
return *this;
}
String & String::Copy(const char otherVar []) {
delete[] Fazah;
Letters = strlen (otherVar);
Slots = Letters;
Fazah = new char [Slots + 1];
return *this;;
}
String & String::Conc(const String & otherVar) {
//delete[] Fazah;
Letters = Letters + otherVar.Letters;
Slots = Slots + otherVar.Slots;
Fazah = new char [Slots + 1 ];
return*this;
}
String & String::Conc(const char otherVal[]) {
Slots = Slots + Letters;
Letters = Letters + strlen(otherVal);
Fazah = new char [Slots + 1];
return* this;
}
int main() {
String Str2("abcdefg");
String Len(Str2);
}
I've been learning c++ for a few weeks now so I'm still relatively new at this. there's been these times where i'm just not sure what to look up to fix my issue, this is one of those times. This is not even a syntax error so it makes it more difficult to fix.
This is probably because I'm still quite new at this; in my head String Len(Str2) should return the length of the string, but it doesn't it only returns the cout <<"Copy const"<< endl . Not really sure what to do here.
The line
String Len(Str2);
creates another instance of String. It does not call the Len member function. You need to use:
size_t len = Str2.Len();
To print it out, in main, change:
String Len(Str2);
Into:
std::cout << Str2.Len() << std::endl;
That is not how you call a member function.
String Len(Str2); means that you are just creating another String by the name of Len, to which the contents of Str2 will be copied, when the copy constructor String::String (const String & otherVar), that you have written will be called.
You should use Str2.Len()to call the appropriate member function inline size_t String::Len ()const that you have written.
Then you should use cout to print it on the console:
std::cout<<Str2.Len();
A function returns a pointer and a length (via the arguments) from an unknown DLL.
Result = SpamnEggs( &pBytes, &nBytes )
The pointer points to a valid memory address at which are nBytes sequential bytes.
These bytes contain valid ascci values for text. There is no null termination!
I am tasked with "ovelaying" a string type of some sort in as few simple operations in generic C++ code (without complex libraries or using byte) before output:
cout << sresult
Added:
without copying the bytes as this is a large buffer that must be traversed.
Prototype:
int SpamnEggs( void* pBytes, void* nBytes );
becomes
int SpamnEggs( char** pBytes, int* nBytes );
Many thanks all. Great answers and all very valid.
You can copy the raw memory and add the string terminating character yourself:
char* newStr = new char[size + 1];
memcpy ( newStr, source, size );
newStr[size] = "\0";
cout << newStr;
Without copying memory, you can create a class that holds the pointer and length as members and overload the stream operator to print only length characters:
class MyString
{
void* _pBuf;
int _length;
public:
MyString(void* pBuf, int length)
{
_pBuf = pBuf;
_length = length;
}
friend ostream& operator <<(ostream &os,const MyString& obj);
};
ostream& operator <<(ostream &os,const MyString& obj)
{
const char* pChar = (const char*)obj._pBuf;
for ( int i = 0 ; i < obj._length ; i++ )
{
os << pChar[i];
}
return os;
}
Example usage:
char* x = "blablabla";
int length = 3;
MyString str(x,length);
cout << str;
You can just construct a std::string from the pointer and a length.
std::string sResult(pBytes, nBytes);
std::cout << sResult;
(assuming pBytes is a char* pointer, otherwise you need a small cast).
How about something like this (untested) code:
class my_pointer_string
{
friend std::ostream &operator<<(std::ostream &, const my_pointer_string &);
public:
my_pointer_string(void *ptr, size_t len)
: m_pointer(ptr), m_length(len)
{ }
private:
void *m_pointer;
size_t m_length;
};
std::ostream &operator<<(std::ostream &os, const my_pointer_string &str)
{
char *string = reinterpret_cast<char *>(str.m_pointer);
for (size_t i = 0; i < str.m_length; i++)
os << *string++;
return os;
}
What you would have to do is
a) Create some class that encapsulates the char pointer and the size.
b) Write a << operator for that class to output its content to a stream.
EDIT: In contrast to the response by Bo Persson this would not imply copying the source data.