I have a class named Fstring, it has a wchar_t* in it.
I wrote the following to copy the string literal into Fstring:
#include <iostream>
using namespace std;
class Fstring{
wchar_t *arr;
public:
Fstring& operator = (const wchar_t temp[])
{
delete [] arr;
arr=new wchar_t[wcslen(temp)];
for(int i=0;i<=wcslen(temp);i++)
arr[i]=temp[i];
return *this;
}
};
int main()
{
Fstring test=L"Hello World";
return 0;
}
But it did not work. The compiler gave me the following error:
error C2440: 'initializing' : cannot convert from 'const wchar_t [12]'
to 'Fstring'
I'm really confused, I googled "Overloading operators" but all of results have the same way I used to overload the operator. So why does this not work?
When you see Type name = initializer it does not use the assignment operator. It is declaring a variable and is therefore initialization(technically copy-initialization or copy-list-initialization). That means it calls a constructor. Since you do not have a constructor that takes a const wchar_t* you will get an error.
What you need is to implement a constructor that takes a const wchar_t* and initialize arr with that. That would look like
Fstring(const wchar_t temp*) : arr(new wchar_t[wcslen(temp) + 1])
{
size_t size = wcslen(temp);
for(int i = 0; i < size; i++)
arr[i] = temp[i];
arr[size] = L'\0'
}
You are also going to have to implement a copy constructor. For more on why see What is The Rule of Three?
Do note that you are reinventing the wheel. If you want a wide character string you can use std::wstring which has all this done for you.
Related
I have just started learning C++ a few days back. I was given an assignment to demonstrate + operator overloading to concatenate two strings. I came up with this solution:
#include <iostream>
using namespace std;
class Strcpy{
private:
char* wrd;
int len;
public:
Strcpy();
Strcpy(char* );
void Display();
friend Strcpy operator + (Strcpy, Strcpy);
friend Strcpy concatinator(Strcpy, Strcpy);
};
Strcpy :: Strcpy(){
wrd = '\0';
len = 0;
}
Strcpy :: Strcpy(char* w){
int i; len = 0;
for(i = 0; w[i] != '\0' ; i++)
len ++;
wrd = w;
}
void Strcpy :: Display(){
cout << "\nOutput: " << wrd << " "<< len;
}
Strcpy operator + (Strcpy obj1, Strcpy obj2){
Strcpy temp;
int i;
temp.wrd = new char[obj1.len + obj2.len];
temp = concatinator(temp, obj1);
temp = concatinator(temp, obj2);
temp.wrd[temp.len] = '\0';
return temp;
}
Strcpy concatinator(Strcpy obj, Strcpy temp){
for(int i = 0; temp.wrd[i] != '\0'; i++)
{
obj.wrd[obj.len] = temp.wrd[i];
obj.len++;
}
return obj;
}
int main(){
Strcpy word, word_I("Hello"), word_II("World");
word = word_I + word_II;
word.Display();
return 1;
}
Some things to be noted:
deprecated conversion from string constant to 'char*' [-Wwrite-strings] I realize this is being caused because I am converting an immutable type to a mutable one but what alternative approach can I try to get rid of this.
I want to avoid using friend functions, but the overloaded operator needs two arguments which isn't possible if it remains a class member.
The following line works the same even if it is changed, why is this happening:
temp.wrd = new char[obj1.len + obj2.len];
//changed to
temp.wrd = new char[//any number here];
I want avoid using string functions if that is possible at all.
Whenever i try taking an input in the following form, it crashes:
char* Strcpy :: get(){
char* temp;
cin >> temp;
return temp;
}
int main(){
Strcpy word;
Strcpy word_I(word.get()), word_II(word.get());
word = word_I + word_II;
word.Display();
return 1;
}
Lastly, I would appreciate any help that would help me improve on the existing solution and some explanation so as to why it is better and the mistakes I am making.
deprecated conversion from string constant to 'char*' [-Wwrite-strings] I realize this is being caused because I am converting an immutable type to a mutable one but what alternative approach can I try to get rid of this.
You never modify *w, so you can use a pointer to const instead.
I want to avoid using friend functions, but the overloaded operator needs two arguments which isn't possible if it remains a class member.
The first argument of a member operator overload is the implicit this pointer. If you declare Strcpy Strcpy::operator+(const Strcpy&) const, it will be a binary operator. That said, the friend operator is probably a better approach.
The following line works the same even if it is changed, why is this happening:
temp.wrd = new char[obj1.len + obj2.len];
//changed to
temp.wrd = new char[//any number here];
It will work as long as "any number" is large enough to contain the entire string. If you write outside of the bounds, the behaviour is undefined.
Whenever i try taking an input in the following form, it crashes:
char* temp;
cin >> temp;
The stream extraction operator requires that a char* passed to it must point to an array sufficiently large to contain the user input. You forgot to initialize temp, so the requirement is not satisfied. As a result, the behaviour of the program is undefined. Solution: Allocate some memory and initialize temp to point to that memory.
The same bug occurs the constructor Strcpy(char*). You don't initialize this->wrd, but you dereference it. Therefore the behaviour is undefined. The solution is the same as above.
If I understood this right
I want to avoid using friend functions, but the overloaded operator
needs two arguments which isn't possible if it remains a class member.
your statement is wrong.
Sample for a binary + operator in a class:
#include <iostream>
class Int {
private: int _i;
public:
Int(int i = 0): _i(i) { }
Int operator + (const Int &i) const
{
return Int(_i + i._i);
}
int get() const { return _i; }
};
int main(int, char**)
{
Int i1(1), i2(2);
Int i;
i = i1 + i2;
std::cout << "i: " << i.get() << std::endl;
return 0;
}
Compiled and tested with gcc on cygwin:
$ g++ -o test-op-plus test-op-plus.cc
$ ./test-op-plus.exe
i: 3
I want to write a function which takes as input a pointer to a vector pointer which point to a string (Dictionary) and a pointer which points to a char (p). The function will check if the char is in the Dictionary and if it isn't there it adds the p in the vector Dictionary.
My code:
#include <iostream>
#include <string>
#include <vector>
using std::string;
using std::vector;
std::vector<string *> dictionary;
void manageDictionary(vector<string *> * dictionary, char *p) {
for (unsigned int i = 0; i < (*dictionary).size(); i++) {
string * pstring = (*dictionary).at(i);
if ((*pstring).compare(p)) {
(*dictionary).push_back(p);
}
}
}
However, the visual studio compiler shows I have an error in the if statement just before the push_back method (.). When I hover on the error, it says "no instance of overloaded function".
I added the std::vector<string *> dictionary; at the beginning, still cannot figure out where the problem is.
dictionnary is a vector of std::string*. std::string* and char* are totally unrelated types. To convert from char* to std::string* will require you to create a new string that contains the value of p for your dictionnary, rather than passing a char* directly. This change will allow your example to compile, but the resulting function is error prone.
#include <string>
#include <vector>
using std::string;
using std::vector;
void manageDictionnary(vector<string *> * dictionnary, char *p) {
for (unsigned int i = 0; i < (*dictionnary).size(); i++) {
string * pstring = (*dictionnary).at(i);
if ((*pstring).compare(p)) {
(*dictionnary).push_back(new string(p));
// Make a new string ^^^^^^^^^^
}
}
}
This solution will require you to delete your strings manually which is not the way things are done in c++. Changing from std::vector<std::string*> to simply std::vector<std::string> will solve this problem, and avoid you headaches in the future. There are other unnecessary pointers that can be removed. Since at(i) returns a string& then we should change pstring to string&. Since dictionnary is not optional (can't be nullptr) and always points to the same vector we can also change it to a vector<string>&.
void manageDictionnary(vector<string> & dictionnary, char *p) {
for (unsigned int i = 0; i < dictionnary.size(); i++) {
string & pstring = dictionnary.at(i);
if (pstring.compare(p)) {
dictionnary.push_back(p);
}
}
}
This latest version will work fine and is much more in line with c++'s philosophy for resource management. I recommend you read on a few topics :
Standard algorithms like std::find.
Range-based for loops.
const-correctness.
pointer vs reference.
Additionally, consider using std::set<string> or std::unordered_set<string> for a more convenient representation of a dictionnary.
In the future, note that the preferred way to access a pointer's methods is ptr->foo() rather than (*ptr).foo().
The assignment is to create a class that implements a dynamic cstring (null-terminated char array).The default constructor should create an empty array and there should also be an overloaded constructor that creates an array of size n.There should also be a function that will grow the array to a larger size (he said that this should be in the class but we will not utilize it until a later assignment). We're also supposed to create two versions of this class. In one version, we will overload the equivalency operator as a member function, and in the second version, we will overload the equivalency operator as a non-member function.
Something feels weird to me because this just seems way to easy.
For the member version, I set it to return true if the two class sizes were equal.
bool CSTR::operator ==(const CSTR & rhs) {
return (size == rhs.size);
}
For the non-member version, I just created a member function to return it's size as an integer and then compare them when the operator is overloaded.
bool operator ==(const CSTR2 & CSTR2_1, const CSTR2 & CSTR2_2) {
return (CSTR2_1.getSize() == CSTR2_2.getSize());
}
I'm just kind of terrified to turn this in without any outside input because this solution of mine seems way too simple compared to everything we have been going over in class. I know we are going to expand on this program for a later assignment, but if any of you see anything that I'm missing here, some input would be awesome.
Here is the code I'm trying to use to compare the cstring. Note: there is nothing in the assignment description that says anything about inputting values into the cstrings.
#include "CSTR.h"
#include <cstring>
using namespace std;
class CSTR {
public:
CSTR();
CSTR(unsigned int n);
~CSTR();
bool operator ==(const CSTR & rhs);
private:
unsigned int size;
char *elems;
bool grow(unsigned int newSize);
};
=================================
CSTR::CSTR() {
size = 0;
elems = new char [0];
}
CSTR::CSTR(unsigned int n) {
if (n > 0) {
size = n;
elems = new char [size];
}
else {
size = 0;
elems = new char [0];
}
}
CSTR::~CSTR() {
delete [] elems;
}
bool CSTR::operator ==(const CSTR & rhs) {
return ((elems == rhs.elems) == 0);
}
I've initialized two objects of CSTR with different sizes, and when I test for equivalency it is returning that they are equal.
I'm currently working in Stroustrup's "Principles and practices" book for learning how to program using C++. I'm at a part where they introduce Tokens and show how to use them. I was attempting to do a simple test to make sure I'm constructing the class correctly and using the tokens and vector correctly.
Below is an example of what I've done.
class Test{
public:
char kind;
double value;
Test(char ch)
:kind(ch), value(0){}
Test(char ch, double val)
:kind(ch),value(val){}
};
int main(){
vector<Test>testLoop;
for(char i = 'a'; i < 'k'; i++){
testLoop.push_back(i, 1);
}
cout << testLoop[5].kind << endl << testLoop[5].value;
}
What I'm trying to accomplish (I think) is having a vector of objects that both obtain the members of the class 'Test', do a loop that adds a few of them to the vector 'testLoop', (and puts 1 in all the value members) then prints out the value of testLoop[5].kind and testLoop[5].value.
The specific errors I'm getting are:
|25|error: no matching function for call to 'std::vector<Test>::push_back(char&, int)'|
candidate expects 1 argument, 2 provided
Any and all criticism and help is welcome! - Thankyou
std::vector::push_back takes an object of the type being stored in the vector. So in this case you would need
testLoop.push_back(Test(i, 1));
You can also use std::vector::emplace_back, which takes the type's constructor arguments and constructs an object in the vector directly:
testLoop.emplace_back(i, 1);
Class Test has two constructors.
The constrcutor with one parameter
Test(char ch)
:kind(ch), value(0){}
is called a conversion constructor because it in fact convert an object of type (in this case) char to an object of type Test
So you might call method push_back the following way
for(char i = 'a'; i < 'k'; i++){
testLoop.push_back( i );
}
In this case the compiler would use the conversion constructor because you did not write explicitly
for(char i = 'a'; i < 'k'; i++){
testLoop.push_back( Test( i ) );
}
so the compiler will do this implicitly.
However if you would declare the constructor with the function specifier explicit
explicit Test(char ch)
:kind(ch), value(0){}
then the compiler could not call it implicitly and would issue an error. In this case you have to specify the constructtor explicitly by yourself
for(char i = 'a'; i < 'k'; i++){
testLoop.push_back( Test( i ) );
}
If you use two arguments as in your loop
for(char i = 'a'; i < 'k'; i++){
testLoop.push_back(i, 1);
}
the compiler is not so smart and can not implicitly call the constructor that has two parameters. It is simpler for it to issue an error.
However you could use an initializer list provided that the compiler supports this feature of C++ 2011
for(char i = 'a'; i < 'k'; i++){
testLoop.push_back( { i, 1 } );
}
In this case the compiler could call implicitly the constructor with two parameters.
I'm trying to overload the plus sign to concatenate two strings, but I keep getting an error.
VS 2010 gives an assertion failed message : "Expression: (L "Buffer is too small" && 0)" ; File: f:\dd\vctools\crt_bld\self_x86\crt\src\tcscat_s.inl ; Line: 42 .
What do you think is wrong with my code?
#include "stdafx.h"
class MyString{
int l; // the length of the array pointed by buf
char *buf; //pointer to a char array
public:
...
MyString(char *);
friend MyString operator+(MyString &,MyString &);
...
};
MyString::MyString(char *p)
{
buf=new char[strlen(p)+1];
strcpy_s(buf,strlen(p)+1,p);
l=strlen(p)+1;
}
MyString operator+(const MyString &a,const MyString &b)
{
MyString result("");
result.l=a.l+b.l;
delete[] result.buf;
result.buf=new char[result.l+1];
result.buf[0]='\0';
strcat_s(result.buf,result.l+1,a.buf);
strcat_s(result.buf,result.l+1,b.buf);
return result;
}
int _tmain(int argc, _TCHAR* argv[])
{
MyString a("hello"),b("world"),c("");
c=a+b;
system("pause");
return 0;
}
It work now! Thank you everyone!
strcat_s(result->buf,strlen(a.buf),a.buf);
strcat_s(result->buf,strlen(b.buf),b.buf);
The second parameter of strcat_s is the size of the destination buffer, not the size of the string that shall be appended.
So you need to change that to
strcat_s(result->buf,result->l+1,a.buf);
strcat_s(result->buf,result->l+1,b.buf);
The rest of the operator + implementation is broken as well, as was already noted by others. Newing up an Instance and then returning it by value is nonsense. Just instantiate the result on the stack and return by value.
In operator+ the variable "MyString result" was declared on the stack and it was subsequently returned by reference, which was bad.
Then the OP was edited. The variable "result" was no longer declared on the stack, but instead allocated on the heap. However, then there was a memory leak.
The right thing to do here is to return by value and also declare "MyString result" on the stack. Also make sure you have a copy constructor. And a destructor for that matter.
You should also make your constructor takes a "const char*".
It should be result.buf=new char[result.l+1]; to allow for the null character.