Access class member "directly" like std::string - c++

I would like the following code to be equivalent:
f = "abc";
h.data = f;
EDIT: I'd also like the ability to do the following:
f += "def"; // f.data == "abcdef";
std::string s = f; // s = "abcdef";
std::cout << f << std::endl;
std::cin >> f;
std::vector<std::string> v (f);
v.push_back(h);
// This would be overkill.
printf("%s", (f + std::string("...\n")).c_str());
Would I need to "inherit" std::string or something? (I'm new to this stuff, so could you show me how?)
Here's my class:
class Foo
{
public:
std::string data;
} f, h;

Add an assignment operator:
class Foo
{
public:
std::string data;
Foo & operator=(const std::string & s) { data = s; return *this; }
};
Depending on what you want to return you could also define it like this:
std::string & operator=(const std::string & s) { data = s; return data; }
Or even, in C++0x:
std::string & operator=(std::string s) { data = std::move(s); return data; }
The former lets you write: Foo x, y; y = x = "hello";. The latter lets you write: std::string a, b; Foo x; a = x = b;. Take your pick.

If I understand correctly, you want to be able to do:
Foo f;
f = "abc";
In which case, you will need to overload operator=. Something along the lines of:
class Foo
{
public:
void operator= (const std::string &str) { data = str; }
std::string data;
};

EDIT: I'd also like the ability to do the following: [...]
[ This would have been better served as a new question but I don't think you could have foreseen that. ]
No, you don't need to inherit from std::string. One possible way to do what you want is to add a conversion operator. (I won't address how to implement operator+=, it can be looked up elsewhere.)
class foo {
std::string data;
public:
foo&
operator=(std::string); // See Kerrek's answer for implementation
operator std::string const&() const
{ return data; }
};
This will do what you want. But I strongly advise you not to use that. Surprising implicit conversions are frowned upon; I recommend reading Herb Sutter to learn why.
Alternatively you can make the conversion operator explicit (as in, declaring it explicit operator std::string const&() const;) to suppress implicit conversions. But that's quite less convenient and readable than adding a member function with an appropriate name:
class foo {
// as before
operator std::string const&() const
{ return as_string(); }
std::string const&
as_string() const
{ return data; }
};
foo f;
// Contrast the uses:
// std::string s0 = f; Not ok; would be an implicit conversion
std::string s0(f); // Ok; explicit conversion
std::string s1 = f.as_string(); // Ok; std::string s1(f.as_string()) works too
std::vector<std::string> v;
// v.push_back(f); Not ok; would use an implicit conversion
v.push_back(static_cast<std::string const&>(f)); // Ok; inconvenient
v.push_back(f.as_string()); // Ok; convenient
Whatever you choose, I still recommend implementing appropriate operators for working with streams:
std::ostream&
operator<<(std::ostream& os, foo const& f)
{
return os << f.as_string();
}
std::istream&
operator>>(std::istream& is, foo& f)
{
std::string extracted;
if(is >> extracted) {
f = std::move(extracted);
}
return is;
}

Overload the = operator.

You can overload the operator.
But I do subscribe to ESA rules about programming. Anything above the simple stuff (eg. I/O, strings, numbers, booleans) get the objects to have member functions. Makes the code more readable and maintainable.
See http://www.esa.int/TEC/Software_engineering_and_standardisation/TECRFBUXBQE_2.html

Related

C++ operator overloading [], where is the data parameter to assign?

I want to add a overload the operator [] in my class. Operator overloading is not something I've had to do before.
I want to write an implementation to do the following:
myclass a;
a["test"] = 123;
int test = a["test"];
So far in my class the prototype looks like this:
string operator[](const char* cpszLabel);
The implementation isn't complete and looks like this:
string myclass::operator[](const char* cpszLabel) {
string strContent;
if ( cpszLabel != nullptr ) {
}
return strContent;
}
What I'm not sure about is how to reference the data that is being assigned or does this require overloading the '=' too?
I've added an overload for the '=' operator, but this doesn't get called:
Prototype:
string operator=(int intData);
Implementation:
string myclass::operator=(int intData) {
char szString[24];
sprintf(szString, "\"%d\"", intData);
return string(szString);
}
You need to arrange things so operator[](const char* cpszLabel) returns a reference to something in your class.
int& operator[](const char* cpszLabel);
is probably a better prototype.
You can then modify that "something" in your class via that reference. To be honest though what you want can be achieved with
typedef std::map<std::string, int> myclass;
and most folk don't bother with the typedef, especially now that we have auto. If you want to use a std::map as a member variable in the class (in order to reduce functionality &c.), then the following is a starting point:
class myclass
{
std::map<std::string, int> m_data;
public:
int& operator[](const char* cpszLabel)
{
return m_data[cpszLabel];
}
};
In a["test"] = 123;, the "receiver" of the assignment is the object that's returned from the lookup, which is a string.
You can't overload string's assignment operator.
But, as is well known, every problem can be solved by introducing a level of indirection.
You can store a type of your own instead of std::string, and let that handle the conversion.
A very small example as illustration:
struct Data
{
template<typename T>
Data& operator=(const T& rhs)
{
std::ostringstream os;
os << rhs;
value = os.str();
return *this;
}
operator const char*() const { return value.c_str(); }
std::string value;
};
struct Container
{
Data& operator[] (const std::string& s) { return table[s]; }
std::map<std::string, Data> table;
};
int main()
{
Container cont;
cont["foo"] = "bar";
cont["baz"] = 123;
cont["goo"] = 5.5;
for (auto v: cont.table)
{
std::cout << v.first << " --> " << v.second << '\n';
}
}
Output:
baz --> 123
foo --> bar
goo --> 5.5

Implement type casting from one class to another

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

C++ Templates and operator overloading

I am learning templates and operator overloading. I have written some code but I am confused... Let me explain...
template <class T>
class tempType
{
public:
T value;
bool locked;
tempType():locked(false)
{
value = 0;
}
T operator=(T val)
{
value=val;
return value;
}
tempType<T> operator=(tempType<T> &val)
{
value=val.value;
return *this;
}
operator T()
{
return value;
}
};
And I did...
int main(void)
{
tempType<int> i;
tempType<bool> b;
tempType<float> f;
i.value = 10;
i = i + f;
return 0;
}
What code I need to write in order to execute
tempType<T> operator=(tempType<T> &val){}
Also, I why operator T() is required?
Unless you implement move semantics, operator= should always take a const & reference to the source value. It should also return a reference to the modified object.
tempType & operator=(T const & val)
{
value=val;
return * this;
}
operator T is an implicit conversion function which allows any tempType object to be treated as an object of its underlying type T. Be careful when specifying implicit conversions that they won't conflict with each other.
An implicit conversion function usually shouldn't make a copy, so you probably want
operator T & ()
{
return value;
}
operator T const & () const
{
return value;
}
Given these, you shouldn't need another overload of operator = because the first overload will simply be adapted by the conversion function to a call such as i = b;.
If a series of conversions will result in the operator=(T const & val) being called, you should avoid also defining operator=(tempType const & val) because the overloads will compete on the basis of which conversion sequence is "better," which can result in a brittle (finicky) interface that may refuse to do seemingly reasonable things.
I think I know all the answers so I might as well post full response.
To override default operator= you should declare it as tempType<T> operator=(const tempType<T> &val){}. Now you need to call the method explicitly via i.operator=(other_i).
If you correct the declaration you can use it like this:
tempType<int> i;
tempType<int> other_i;
i = other_i; // this is what you just defined
The operator T() is called a conversion operator. It is kind of reverse or counter part of the conversion constructor which in your case would be tempType(const &T value).
It is used to convert a class object into a given type. So in your case you would be able to write:
tempType<int> i;
int some_int;
some_int = i; // tempType<int> gets converted into int via `operator int()`
template <class T>
class tempType
{
public:
T value;
bool locked;
tempType() : value(), locked(false)
{
value = 0;
}
//althought legal, returning something different from tempType&
//from an operator= is bad practice
T operator=(T val)
{
value=val;
return value;
}
tempType& operator=(const tempType &val)
{
value=val.value;
return *this;
}
operator T()
{
return value;
}
};
int main(void)
{
tempType<int> a;
tempType<int> b;
a = b;
return 0;
}
in the code, a = b calls the operator.
As for the second question, the operator T() is not needed "by default". In your example, it is used when you write i+f:
i is converted to an int
f is converted to a float
the operation (+) is performed
T tempType<int>::operator=(T val) is called for the assignement

C++ multiple operator=()

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.

C++ class conversion possible?

I have the following code:
class B {
public:
B(const std::string& str):m_str(str) { }
B(const B& b):m_str(b.m_str) { }
B& operator=(const B& b) { m_str = b.m_str; return *this; }
private:
std::string m_str;
};
main()
{
std::string a = "abc";
B b(a);
}
class B belongs to the client. I can't change it and I may not even know its specific name ("B" is simply an example); all I know is there's a client class that accepts a std::string for its constructor. Now I want to change the type of "a" in main() from std::string to A, as defined below:
class A {
public:
A(const std::string& str):m_str(str) { }
A(const char *str):m_str(str) { }
A(const A& a):m_str(a.m_str) { }
A& operator=(const A& a) { m_str = a.m_str; return *this; }
private:
std::string m_str;
};
So now I have a new main():
main()
{
A a = "abc";
B b(a);
}
This can't compile properly as it is. Is there anything I can do without changing the new main()? I can't change class B, and class A should not reference class B in any way.
Thanks!
add an cast operator
class A {
public:
....
operator const std::string()
{
return m_str;
}
Add user-defined conversion function as:
class A
{
public:
//other code
operator std::string()
{
return m_str;
}
//...
};
This allows you write these:
B b(a); //which is what you want
std::string s = a; //this is also okay;
void f(std::string s) {}
f(a); //a converts into std::string, by calling user-defined conversion function
However you cannot write this:
const A ca("hi");
std::string s = ca; //error
Its because ca is a const object which cannot invoke non-const user-defined conversion function.
Note the user-defined conversion function returns the string by value which means it returns a copy of the original string. So you may want to avoid this by defining it as:
operator const std::string &() const
{
return m_str;
}
Now, with this you can write this:
const A ca("hi");
std::string s = ca; //ok
A a("hi");
std::string s = a; //ok
How about
int main() //note the correct declaration of main
{
A a = "abc";
B b(a.GetString()); //GetString returns m_str;
}
By the way, all your definitions of copy constructors and copy-assignment operators coincide with the definitions the compiler would have auto-generated for you.
Edit
I just noticed your constraint that main() should not change. In this case you can define a conversion function from A to string (but it can be dangerous, note).
class A
{
...
operator std::string() const {return m_str; }
};
Add this to class A:
operator std::string () { return m_str; }