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; }
Related
I have code like below and I need to write a global function overloading the addition operator for objects of this class so that the resulting object represents the concatenation of two strings separated by the '+' sign. Can someone help me?
class A {
char* str;
// ...
};
Such operator should have access to content of class and to create a new instance of class A which it returns. Assuming there is no public interface to access str such operator have to be a friend function with signature similar to one below
class A {
char* str;
// ...
friend A operator+ (const A& arg1, const A& arg2)
{
A temp{arg1}; // assuming that A have a copy constructor
// perform concatenation of temp and arg2 here
return temp;
}
};
Try something like this:
class A
{
char* str;
// ...
public:
A(const char *s = nullptr) : str(nullptr) {
if (s) {
str = new char[strlen(s)+1]);
strcpy(str, s);
}
}
A(const A &src) : A(src.str) {}
A(A &&src) : str(src.str) { src.str = nullptr; }
~A() { delete[] str; }
A& operator= (A rhs) {
A temp{std::move(rhs)};
std::swap(str, temp.str);
return *this;
}
friend A operator+ (const A& arg1, const A& arg2)
{
A temp;
temp.str = new char[strlen(arg1.str)+1+strlen(arg2.str)+1];
sprintf(temp.str, "%s+%s", arg1.str, arg2.str);
return temp;
}
};
That being said, you really should use std::string instead of char*:
class A
{
std::string str;
// ...
public:
A(const std::string &s = "") : str(s) {}
friend A operator+ (const A& arg1, const A& arg2)
{
return A{arg1.str + "+" + arg2.str};
}
};
I need to be able to initialize a const member inside the constructor, which counts up every time I create a new object. I was shown in school how its suppose to work, but I'm getting errors all the time. It's something to do with the copy constructor.
Here's the code and the compiler errors:
class kunde {
public:
kunde(string name, int alter);
kunde(const kunde& orig);
~kunde();
int GetAlter() const;
string GetName() const;
const int GetKnr() const;
private:
string name;
int alter;
const int knr;
static int cnt;
static int MaxKnr;
};
int kunde::cnt = 0;
int kunde::MaxKnr = 1000;
kunde::kunde(string name, int alter):knr(MaxKnr++) {
this->name = name;
this->alter = alter;
}
kunde::kunde(const kunde& orig):knr(MaxKnr++){
this->name = orig.name;
this->alter = orig.alter;
}
kunde::~kunde() {
}
int kunde::GetAlter() const {
return alter;
}
string kunde::GetName() const {
return name;
}
const int kunde::GetKnr() const {
return knr;
}
main.cpp: In function 'int main(int, char**)':
main.cpp:35:15: error: use of deleted function 'kunde& kunde::operator=(const kunde&)'
v[0] = v[1];
^
In file included from main.cpp:17:0:
kunde.h:19:7: note: 'kunde& kunde::operator=(const kunde&)' is implicitly deleted because the default definition would be ill-formed:
class kunde {
^~~~~
kunde.h:19:7: error: non-static const member 'const int kunde::knr', can't use default assignment operator
knr is suppose to be an account number. each time you create an object it creates a new const account number which stays.
As stated in comments, since knr is const, the compiler cannot generate a default copy-assignment operator= for the class, which is exactly what the compiler is complaining about for the v[0] = v[1]; statement:
note: 'kunde& kunde::operator=(const kunde&)' is implicitly deleted because the default definition would be ill-formed
const members cannot be re-assigned once initialized, thus cannot be copied.
The elements in a vector must be CopyAssignable and CopyConstructible (at least until C++11), but your class does not have a viable copy-assignment operator=, so it is not CopyAssignable (and it is not MoveAssignable in C++11 either, since a viable move-assignment operator= can't be generated, either).
The solution is to implement a copy-assignment operator= (and optionally a move-assignment operator=) that ignores knr, eg:
class kunde {
public:
kunde(string name, int alter);
kunde(const kunde& orig);
kunde(kunde&& orig);
...
kunde& operator=(const kunde& rhs);
kunde& operator=(kunde&& rhs);
...
private:
string name;
int alter;
const int knr;
...
};
kunde::kunde(string name, int alter)
: knr(MaxKnr++), name(name), alter(alter)
{
}
kunde::kunde(const kunde& orig)
: knr(MaxKnr++), name(orig.name), alter(orig.alter)
{
}
kunde::kunde(kunde&& orig)
: knr(MaxKnr++), name(std::move(orig.name)), alter(orig.alter)
{
}
kunde& kunde::operator=(const kunde& rhs)
{
if (&rhs != this)
{
name = rhs.name;
alter = rhs.alter;
// CAN'T BE DONE, SO IGNORE IT
// knr = rhs.knr;
}
return *this;
}
kunde& kunde::operator=(kunde&& rhs)
{
name = std::move(rhs.name);
alter = rhs.alter;
// CAN'T BE DONE, SO IGNORE IT
// knr = rhs.knr;
return *this;
}
I can't understand why a.funct() can be the left operand of the assignment operator even if funct() is not returning a l-value reference.
class A
{
public:
A funct () {A x; return x;}
};
int main ()
{
A a,b; a.funct()=b;
}
In the auto generated methods for the class, there is
A& operator = (const A&);
which make a.funct() = b legal.
To forbid affectation to rvalue, you may, since C++11, write and implement
A& operator = (const A&) &; // Note the last &
so assignation would only work for lvalue.
In the code, funct should return a variable that can be assigned to.
Note that the code in funct is very dangerous too if it were to be returned by reference; the local variable x will go out of scope once the function ends and the variable returned will cause undefined behaviour as its destructor will have been called.
Your assumption is wrong. Your code is perfectly valid.
Try this code:
#include <string>
#include <iostream>
class A
{
std::string m_name;
public:
A(const std::string& name) :m_name(name) {}
A funct() { A x("intern"); return x; }
A& operator=(const A& a)
{
m_name += a.m_name;
return *this;
}
void print() { std::cout << m_name << std::endl; }
};
int main()
{
A a("A"), b("B"); (a.funct() = b).print();//prints "internB"
}
I need to have set as a class member variable, but also need it's comparision function object use the attributes of the class.
class Example
{
int _member1;
set<string, MyCmp> _myNameSet;
class MyCmp
{
Example& myEx;
MyCmp( const Example& ex) {
myEx = ex;
}
bool operator() (const string& lhs, const string& rhs)
{
/// Use "_member1" here ...
myEx._member1;
/// Do something ....
}
}
};
So here my question is, how do i pass the Example object as an argument to the MyCmp constructor? Since the "_myNameSet" is an member variable.
If it was not an member variable, there is a way i know:
void Example::functionBlah()
{
MyCmp obj(&(*this));
set<String, MyCmp> myLocalSet(obj);
}
You may use initializer list in constructor:
class Example
{
public:
Example() : _member1(0), _myNameSet(this) {}
Example(const Example&) = delete;
Example& operator = (const Example&) = delete;
// Other stuff
private:
int _member1;
set<string, MyCmp> _myNameSet;
};
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.