= operator to cast to friend class


G

GF

Hello,

I have a string class, but want to be able to assign it to some other
frameworks class:

I think I need to provide an global operator function, but I can't figure
out how to declare it.


// CODE
#include <string>
class mystring
{
public:
mystring():m_data(NULL)
{clear();}
mystring(const char* s)
{m_data=new char[strlen(s)+1]; strcpy(m_data, s);}
// copy ctor from std::string
mystring(const std::string& s)
{*this = s;}
// = operator from std::string
const mystring& operator=(const std::string& s)
{clear(); *this=mystring(s.c_str() ); return *this;}
void clear()
{delete[] m_data; m_data=new char[2]; strcpy(m_data, "");}
private:
char* m_data;
};

void test()
{
mystring ms;
std::string st;
ms = st; // fine!
st = ms; // fail
}
// /CODE


Many thanks,
-Gernot
 
Ad

Advertisements

S

Stefan van Kessel

Hello,

I have a string class, but want to be able to assign it to some other
frameworks class:

I think I need to provide an global operator function, but I can't
figure out how to declare it.


// CODE
#include <string>
class mystring
{
public:
mystring():m_data(NULL)
{clear();}
mystring(const char* s)
{m_data=new char[strlen(s)+1]; strcpy(m_data, s);}
// copy ctor from std::string
mystring(const std::string& s)
{*this = s;}
// = operator from std::string
const mystring& operator=(const std::string& s)
{clear(); *this=mystring(s.c_str() ); return *this;}
void clear()
{delete[] m_data; m_data=new char[2]; strcpy(m_data, "");}
private:
char* m_data;
};

void test()
{
mystring ms;
std::string st;
ms = st; // fine!
st = ms; // fail
}
// /CODE

For the assignment st = ms; to work you need to implement the conversion
operator to std::string

class mystring{
// [...]
public:
operator std::string()
{
return std::string(m_data);
}
};

Use conversion operators judiciously though because they can lead to
surprising behavior.

Btw, just in case you didn't write your example code only to showcase
your question and aren't aware of it: mystring is full of bugs, including

- it leaks memory
- the compiler generated copy constructor won't work correctly
- mystring(const std::string& s) will delete an uninitialize pointer
 
V

Victor Bazarov

I have a string class, but want to be able to assign it to some other
frameworks class:

I think I need to provide an global operator function, but I can't
figure out how to declare it.


// CODE
#include <string>
class mystring
{
public:
mystring():m_data(NULL)
{clear();}
mystring(const char* s)
{m_data=new char[strlen(s)+1]; strcpy(m_data, s);}
// copy ctor from std::string
mystring(const std::string& s)
{*this = s;}
// = operator from std::string
const mystring& operator=(const std::string& s)
{clear(); *this=mystring(s.c_str() ); return *this;}

An assignment operator that returns a reference to *const*? Does not
make sense. If you know you can assign to it, you should be able to
call a mutating member on the result of the assignment expression,
that's just common sense. Not to mention you should be able to do

(a = b) = c;

which is impossible when returning a const ref to self from a member
that is non-const.
void clear()
{delete[] m_data; m_data=new char[2]; strcpy(m_data, "");}
private:
char* m_data;
};

Your code does not adhere to the Rule of Three. Read up on it.
void test()
{
mystring ms;
std::string st;
ms = st; // fine!
st = ms; // fail
}
// /CODE

V
 
G

GF

Hi,

code was just to show the problem - no real life code.

Now I have an ambigiousity. It could be assignment
std::string::eek:perator=(const char*)
or
mystring::eek:perator std::string()const;

Is there a way to fix that?

// CODE
class mystring
{
public:
mystring():m_data(NULL)
{clear();}
mystring(const char* s)
{m_data=new char[strlen(s)+1]; strcpy(m_data, s);}
// copy ctor from std::string
mystring(const std::string& s):m_data(NULL)
{*this = s;}
~mystring()
{delete [] m_data;}

operator std::string() const {return std::string(m_data);}
operator const char*()const {return m_data;}

// = operator from std::string
const mystring& operator=(const std::string& s)
{clear(); *this=mystring(s.c_str() ); return *this;}
void clear()
{delete[] m_data; m_data=new char[2]; strcpy(m_data, "");}
private:
char* m_data;
};

void test()
{
mystring ms;
std::string st;
ms = st; // fine!
st = ms; // fail - ambigious
}

// /CODE





"Stefan van Kessel" schrieb im Newsbeitrag

Hello,

I have a string class, but want to be able to assign it to some other
frameworks class:

I think I need to provide an global operator function, but I can't
figure out how to declare it.


// CODE
#include <string>
class mystring
{
public:
mystring():m_data(NULL)
{clear();}
mystring(const char* s)
{m_data=new char[strlen(s)+1]; strcpy(m_data, s);}
// copy ctor from std::string
mystring(const std::string& s)
{*this = s;}
// = operator from std::string
const mystring& operator=(const std::string& s)
{clear(); *this=mystring(s.c_str() ); return *this;}
void clear()
{delete[] m_data; m_data=new char[2]; strcpy(m_data, "");}
private:
char* m_data;
};

void test()
{
mystring ms;
std::string st;
ms = st; // fine!
st = ms; // fail
}
// /CODE

For the assignment st = ms; to work you need to implement the conversion
operator to std::string

class mystring{
// [...]
public:
operator std::string()
{
return std::string(m_data);
}
};

Use conversion operators judiciously though because they can lead to
surprising behavior.

Btw, just in case you didn't write your example code only to showcase
your question and aren't aware of it: mystring is full of bugs, including

- it leaks memory
- the compiler generated copy constructor won't work correctly
- mystring(const std::string& s) will delete an uninitialize pointer
 
S

Stefan van Kessel

Hi,

code was just to show the problem - no real life code.

Now I have an ambigiousity. It could be assignment
std::string::eek:perator=(const char*)
or
mystring::eek:perator std::string()const;

Is there a way to fix that?

// CODE
class mystring
{
public: [...]
operator std::string() const {return std::string(m_data);}
operator const char*()const {return m_data;}
[...]


Supplying a operator const char*() is probably a bad idea. If you are
intent on doing that, you could just drop the operator std::string since
const char* is convertible to std::string by virtue of it's constructor
taking const char* anyway.

It's not just an accident that std::string has a member function, not a
operator to get its c_str though. For example your class is now also
convertible to bool and it won't be false iff the string is empty as one
might expect but iff m_data is 0.
 
G

GF

Supplying a operator const char*() is probably a bad idea. If you are
intent on doing that, you could just drop the operator std::string since
const char* is convertible to std::string by virtue of it's constructor
taking const char* anyway.

Ah, that did the trick. Many thanks. I know of the hazard of the const char*
operator, but it's so comfortable.
 
Ad

Advertisements

R

Rui Maciel

Victor said:
Your code does not adhere to the Rule of Three. Read up on it.

Not adhering to the rule of three isn't the problem. In fact, not only it's
nothing more than a rule of thumb but also it can be argued that it wasn't
broken at all in this case, as no destructor or copy constructor was
declared.[1]

The one thing which was broken was RAII. It's bad form to let a class
allocate memory from the heap and then fail to provide a proper destructor
to clean that up.


Rui Maciel

[1] http://www.drdobbs.com/c-made-easier-the-rule-of-three/184401400
 
Ad

Advertisements

J

Jorgen Grahn

.
mystring(const std::string& s)
{*this = s;}
const mystring& operator=(const std::string& s)
{clear(); *this=mystring(s.c_str() ); return *this;}

I didn't pay attention to the rest, but I'd do it the other way
around: implement assignments as copy-and swap:

mystring& operator=(const std::string& s)
{
mystring neu(s);
swap(neu);
return *this;
}

I'd also do what the standard containers do, and have a constructor

template<class Iter>
mystring(Iter first, Iter last);

so I can construct a mystring from *any* decent character sequence.

/Jorgen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top