I'm playing with operator overloading in C++, specifically the assignment operator "=".
So, at a time, I'm able to do this:
MyClass var1;
var1 = "string";
But, it gives me an error when I try to do this:
MyClass var2 = "string";
Somebody knows why? And how can I make it possible?
The second example isn't calling operator=, it's calling a conversion constructor for const char [], or whatever you'd be using it for internally, as long as it can convert from that (e.g. std::string), which doesn't exist as of yet. You can see one implemented in std''OrgnlDave's answer. It's almost identical to
MyClass var2 ("string");
The latter, though, is explicit, whereas the former is implicit. To see the difference, make a constructor and mark it explicit. The code here will work, but yours won't. This can save confusion when you, for example, pass a string by accident instead of a MyClass, and it gets implicitly converted when it isn't even meant to be a MyClass in the first place.
You need to make a constructor for your class, the second example is calling the constructor.
class MyClass {
public:
MyClass(const std::string& what) { } // copy string
};
Related
I am so confused, and I'm sorry if this is obvious. Am I wrong that in the following:
struct MyStruct
{
MyStruct(){};
MyStruct(MyStruct* arg){};
}
MyStruct(MyStruct* arg){}; is a constructor taking one pointer to a MyStruct as argument?
Because I have a problem that this constructor (which I think it is) is being called when I do this:
int main()
{
MyStruct obj;
MyStruct* objPtr;
obj = objPtr;
return 0;
}
When assigning obj to objPtr I expected the compiler to complain, but it doesn't, and instead calls MyStruct(MyStruct* arg); which I thought was a constructor taking a pointer argument.
Any help would be appreciated. Also, if I add a copy assignment operator to the class it still happens.
Edit: Thanks for the answers. It looks like I've got some reading to do on this, and the topic seems to be (for anyone wondering) converting constructors in C++. Also I'm guessing the explicit keyword. Here is a link to an SO question which explains it:
What is a converting constructor in C++ ? What is it for?
The compiler synthesizes an assignment operator for you:
MyStruct& MyStruct::operator=(MyStruct const&) = default;
When it sees the assignment, it finds a candidate for the operator (which is the one it created). Then it sees that it can use your constructor to make a conversion, to a type that will allow the assignment (MyStruct). So it boils down to:
obj = MyStruct (objPtr);
If you want to see the error happen, mark you constructor as explicit:
struct MyStruct
{
MyStruct(){};
explicit MyStruct(MyStruct* arg){};
}
For obj = objPtr;, the complier will try to call MyStruct::operator=() on obj with argument objPtr, which is MyStruct*. There's a candidate, the implicitly declared copy assignment operator MyStruct::operator=(const MyStruct&). MyStruct could be converted from MyStruct* via converter constructor MyStruct::MyStruct(MyStruct*), so it compiles.
If you make the MyStruct::MyStruct(MyStruct*) explicit, compile will fail.
struct MyStruct
{
MyStruct(){};
explicit MyStruct(MyStruct* arg){};
};
When you sasign objPtr to obj, you're assigning a value of type MyStruct* to MyStruct - that's invalid. However, since you have a constructor that takes MyStruct*, it's called to convert the value. It's basically an implicit conversion :)
obj = objPtr;
Will call
obj.MyStruct::operator =(MyStruct(objPtr));
Mark your constructor explicit to avoid this type of unwanted conversion.
I have started to develop with C++ and I have a doubt about copy constructor and assignment operator.
I have this class:
class MyTime
{
private:
unsigned char _hour;
unsigned char _minute;
float _second;
signed char _timeZone;
unsigned char _daylightSavings;
double _decimalHour;
public:
MyTime(unsigned char hour, unsigned char minute, float second, signed char timeZone, unsigned char daylightSavings);
MyTime(const MyTime& copySource);
MyTime& operator=(const MyTime& source);
~MyTime();
unsigned char getHour();
unsigned char getMinute();
float getSeconds();
signed char getTimeZone();
unsigned char getDayLightSavings();
double getDecimalHour();
};
And copy constructor and assignment operator implementation:
MyTime::MyTime(const MyTime& copySource)
{
this->_hour = copySource._hour;
this->_minute = copySource._minute;
this->_second = copySource._second;
this->_timeZone = copySource._timeZone;
this->_daylightSavings = copySource._daylightSavings;
}
MyTime& MyTime::operator=(const MyTime& source)
{
this->_hour = source._hour;
this->_minute = source._minute;
this->_second = source._second;
this->_timeZone = source._timeZone;
this->_daylightSavings = source._daylightSavings;
return *this;
}
Are these implementations required?
I need to make sure that when I assign an instance of MyTime it will create a new instance with its values.
Your copy constructor and assignment operators are just copying the values from copySource and source respectively into your instance.
You're not creating a new instance, just overwriting your instance's values with those of copySource and source.
As it stands, your class doesn't even require writing copy constructor and assignment operator since the compiler will implicitly generate them for you.
This is a feature of the C++ language, I recommend reading more about this here: Copy constructors in C++ (ndMarco: I understand this might not be the easiest source to learn from, but it is one of the most complete and accurately written available).
Copying each member variable from an instance to another is not a deep-copy problem and thus no action is required on your side.
As a follow-up for your studies take a look at the rule of three/five/zero. Start with the rule of three (understand why your class doesn't need any of them and what would happen if it needed one of them) and then move on to understanding C++11 concepts.
One last secondary thing: using a verbose this->member_variable isn't needed in C++ unless you need to make it clear you're referring to a member variable instead of a local one e.g.
class MyClass {
public:
int value = 33;
void function() {
int value = 42; // Now there's confusion
std::cout << value; // 42
}
};
so in your case this-> is not required. Anyway as a style preference you might still use it to make it clear you're referring to a member variable of that class. Just be aware of this small caveat. This is intended as an addition to the fact that you should not name your local variables and class members in the same way (that's a terrible practice).
There are still many things that could be added or built over these concepts but they would steer this post off-topic. Just make your mind on these preliminary concepts and you might call it a day.
No. Your class as it stands does not require copy constructor, assignment operator or destructor. The compiler-generated ones will do exactly what you require.
Also, from a style POV, you don't need all the "this->" stuff to access class members, unless you're choosing bad names for local variables, or are doing complex template-related stuff.
It's fine not to do it, as your compiler should generate them for you. However, this is not that case in all classes. A compiler generated copy constructor/assignment operator will basically just use the = operator for everything, which is not a good case if you are using pointers and dynamic memory:
Take a string class. You have a char* which you reallocate with internal functions inside the string class and assign using functions like copy, e.t.c.
However, if a copy construct/assignment operator is omitted for a class like a string, the compiler should automatically create one, which unlike what you want, will simply point your pointers to the pointer of the class to be copied from, which will cause large errors, as once that class is modified, your string will also be modified as they both point to the same memory. As a result, for classes that you do not want the compiler to use a simple operator= on all the members with, you should define the copy constructor/operator=... otherwise there is no need as long as you have a good compiler
Note: you do not need this-> to access the members as you are not inheriting them from a templated class.
No, your code is equivalent to the default copy-constructor and assignment operator. A compiler will generate these as needed. As a rule of thumb, you need to define your own versions if you use dynamic memory or some objects without copy semantics.
As a simple example, if you write new in your constructor, you will have to write a matching delete in your destructor, and then by the rule of three you will have to do something with a copy-constructor and an assignment operator. If you avoid managing memory manually, you don't have to worry about these.
Is the following assignment valid?
class A {
int a;
public:
A(int k): a(k){}
}
void main() {
A first (5);
A second;
second = first;
}
If it is valid, what happens for second? Does C++ makes a deep copy? Or a shallow copy?
Perhaps you are new to C++, perhaps a student?
You are lucky, since the data member for your A class is an integer. Which is a plain old data type. Called POD for short. BTW: You tagged your question with copy-constructor, but demonstrated in your example an assignment operator.
They are two different things.
A copy constructor makes a new instance based off of another instance. Like this:
class A
{
public:
A(A& other) { ... }
};
An assignment operator looks like this:
class A
{
public:
const A& operator=(const A& other) { ... }
};
Since you did not provide your own assignment operator, the compiler made one for you. In fact the compiler will also make a destructor for you too. Isn't that nice? Well don't always trust your compiler. If your classes have anything beyond Plain old Data, then please get in the habit of providing your own constructors, destructors, assignment operators. It's a rule I live by. I'd hate to have a bug that takes 2 days to track down to say... a memory leak due to my forgetting to deallocate memory in a destructor.
In your case, the compiler made a shallow copy for you. A compiler will never make a deep copy for you. You have to do that yourself.
Since you wrote one form of constructor, compiler will not provide default constructor so your declaration 'A second;' will not compile. You could possibly do A second(0); and then second = first;
Actually,i'm having many doubts regarding string operations.Firstly,
I'm confused regarding the use of copy constructor for string concatenation.Is there a need of copy constructor,or just by using parameterized constructor,it can be done.I mean
class string{
char*p;
int size;
public: string(char *a){
size= strlen(a);
p=new char[size];
strcpy(p,a);
}
The above code,initailizes the object dynamically.
how does pointer work if passed as argument in above code,what if i pass char array a[].
Also,the strcpy copies the string.now if i use operator overloading i.e
string operator+(string c) // i'm defining the function in class definition.
{
string t;
t.size=size + c.size;
t.p=new char[t.size];
strcat(t.p,c.p);
return t;
}
Do i need a copy constructor?and why?
Also can anyone explain me what actually happens when working with pointers to char as in this case.
Secondly,in main() if i declare the objects.Will it be wrong to write
string ob1("Hello world");
or should i proceed as
char *str;
str="Hello world";
Plz do point out the errors in my code snippet's too,if any.when i'm running the program,it stops in between and it promts program has stopped working.
Why so?
Do i need a copy constructor?
In general, a class that manages resources does, and you should provide one (along with a constructor and copy-assignment operator) to make the class useful.
However, you shouldn't just for this operator; but your implementation does...
and why?
Because your operator takes its left-hand argument by value, which requires it to be copied. Take it by reference instead:
string operator+(string const & c) const
(It's a good idea for both operands to be const, both to prevent accidental modification, and to allow the operator to be applied to constant values).
However, if you want to fix the memory leak (by deleting the array in the destructor) then you should either provide or delete the copy constructor and copy-assignment operator to avoid double deletion. See this question for the gory details of making a type copyable.
string ob1("Hello world");
This might fail (with modern compilers) since your constructor takes a non-const char*, while the string literal decays to const char*. You should change the constructor argument to const char* to match (and, in general, always make pointers and references const when you don't need to use them for modification).
boost::shared_array<char const *> x(new char const *[n]);
In the line above (n is integer number not greater than 100) I'm creating char const**(const char**) and putting it to smart pointer x for arrays to be deleted when x is deleted. And for me it is clearly how and why this work.
boost::shared_array<char const *> x = new char const *[n];
Now lets take a look to second line. Here in my opinion we do exactly the same as in first case. Yes at first glance we may seem that here we constructing x via NULL(default value of shared_array constructors parameter) then calling operator=, but this is mistake, and as I know in this case instead of operator= will be called constructor with pointer created by new opeartor.
But in spit of this I'm getting error C2440: 'initializing' : cannot convert from 'const char **' to 'boost::shared_array<T>
The only problem I see this is the explicit constructor of boost::shared_array<T>. But I don't know what is the problem? Why does explicit constructor cause this error? And if the problem is not in explicit constructor, then where, why?
Your guess is correct.
What you're trying to do in the second line is implicitly calling the constructor: you want the C++ compiler to realize that there is a constructor available that accepts a T* and use it. However, since the constructor is marked as explicit, it cannot be invoked this way.
See for example the discussion at http://www.go4expert.com/forums/showthread.php?t=20756.
Yes, the "problem" is that the T* constructor for shared_array is explicit. That forbids constructing with =.
Now lets take a look to second line. Here in my opinion we do exactly
the same as in first case. Yes at
first glance we may seem that here we
constructing x via NULL(default value
of shared_array constructors
parameter) then calling operator=, but
this is mistake, and as I know in this
case instead of operator= will be
called constructor with pointer
created by new opeartor.
That's not entirely true. Here's what actually happens in the general case. Suppose you have
struct A
{
/*explicit*/ A(int){}
};
A a = 7;
This isn't actually equivalent to A a(7). In the A a = 7 initialization, you call 2 constructors, the constructor that takes int to create a temporary, and the copy constructor to initialize a. Of course this is redundant in most cases and the compiler is allowed to omit the copy-constructor call (that is explicitly mentioned in the standard) but nonetheless it requires you to have one regardless of whether it decides to omit the call or not.
struct A
{
/*explicit*/ A(int){}
private: A(A const &){}
};
A a = 7;
Now this will be a compile-time error. If you add some tracing messages to both constructors, you'll most likely see that the copy constructor doesn't get called anyway, but that doesn't matter - it must be there and accessible.
As to why explicit hinders you to call the above syntax must be clear now - because that constructor is called implicitly to initialize the temporary, not a.
HTH and Cheers, :)