In my program, I am trying to use the assignment operator= to assign an object of my class. I am specifically trying to call the assignment operator instead of an implicit constructor (thus the explicit keyword). When I try to compile, I get a C2440 Compiler Error:
class MyClass {
public:
explicit MyClass(double x = 0.) :
m_x(x) {
}
MyClass& operator = (const double& other) {
m_x = other;
/* do something special here */
return *this;
}
private:
double m_x;
};
int main()
{
MyClass my_class = 2.; // C2440
return 0;
}
I guess that the compiler fails trying to call the constructor implicitly (because of explicit). Does anyone have a fix?
MyClass my_class = 2.; is more or less equivalent to MyClass my_class(2.);, but, you marked the constructor as explicit, which prevents C++ from doing that automatically.
So, in the way you've written your code, you cannot really do what you want. You could explicitly call the constructor using:
MyClass my_class(2.); // Explcitly call your constructor
Or, as Ted Lyngmo mentioned in the comments, you can do:
MyClass my_class; // Call your constructor with default argument of 0
my_class = 2.; // then call your assignment operator
Related
I'm familiar with the principle (for example, from this answer and this one) that when a class has a move constructor and/or move assignment operator, its default copy constructor and copy assignment operator are deleted. However, In the examples I've seen, this can be addressed by explicitly defining a new copy constructor and assignment operator.
In my particular case, I have a class which is derived by joint inheritance from a C-style struct and a template class. The copy and move assignment operators are explicitly defined in the template, whilst the copy and move constructors are explicitly defined in the class itself. In other words, everything is defined explicitly, though not all in the same place. Here is some example code:
typedef struct {
int n;
} myStruct;
template <typename T> class myTemplate
{
public:
// Default constructor
myTemplate<T>() : t_n(nullptr) {}
// Cannot create copy or move constructors in template, as cannot
// access the 'n' member directly
// Copy assignment operator
myTemplate<T> & operator=(const myTemplate<T> &source)
{
if (this != &source)
{
*t_n = *(source.t_n);
}
return *this;
}
//! Move assignment operator
myTemplate<T> & operator=(myTemplate<T> &&source)
{
if (this != &source)
{
*t_n = *(source.t_n);
*(source.t_n) = 0;
source.t_n = nullptr;
}
return *this;
}
T* t_n;
};
class myClass : public myStruct, public myTemplate<int>
{
public:
// Default constructor
myClass() : myTemplate<int>()
{
n = 0;
t_n = &n;
}
// Alternative constructor
myClass(const int &n_init) : myTemplate<int>()
{
n = n_init;
t_n = &n;
}
// Copy constructor
myClass(const myClass &source) : myTemplate<int>()
{
n = source.n;
t_n = &n;
}
// Move constructor
myClass(myClass &&source) : myTemplate<int>()
{
n = source.n;
t_n = &n;
source.n = 0;
source.t_n = nullptr;
}
};
int main()
{
myClass myObject(5);
myClass myOtherObject;
// Compilation error here:
myOtherObject = myObject;
return 1;
}
In Visual C++ and Intel C++ on Windows, this works exactly as I'd expect it to. On gcc 4.9.0 in Linux, however, I get the dreaded error message:
g++ -c -std=c++11 Main.cppMain.cpp: In function ‘int main()’:
Main.cpp:78:19: error: use of deleted function ‘myClass& myClass::operator=(const myClass&)’
myOtherObject = myObject;
^
Main.cpp:39:7: note: ‘myClass& myClass::operator=(const myClass&)’ is implicitly declared as deleted because ‘myClass’ declares a move constructor or move assignment operator
class myClass : public myStruct, public myTemplate<int>
Sure enough, the error goes away if I define an explicit copy assignment operator in the class itself, rather than in the template, but that's bothersome to do and undermines the advantage of using the template, since (a) my actual copy assignment operator is a lot bigger than the one shown here and (b) there are a large number of different classes that all share this template.
So, is this simply a bug in gcc 4.9.0, or is this in fact what the standard says should happen?
GCC is correct (and Clang and EDG agree).
myTemplate has a user-declared move constructor, therefore its copy assignment operator is deleted.
You've provided a copy constructor, but not copy assignment operator. Just declare a copy assignment operator for myTemplate and define it as defaulted. That takes one extra line of code.
I have a class that has a few int and a const int member with a constructor defined.
class SomeContainer
{
public:
SomeContainer():
member1(0),
member2(staticMethod())
{}
private:
static int staticMethod();
int member1;
const int member2;
}
I need to create an assignment operator since I use this class in another class MainClass and code
MainClass* p1;
MainClass* p2
{
//...
*p1 = *p2 // fails since SomeContainer doesn't have copy assignment operator
}
Should this code be enough or am I missing anything?
{
SomeContainer(const SomeContainer& other): // copy ctor
member1(other.member1),
member2(other.member2)
{}
SomeContainer& operator=(const SomeContainer& other) // assignment operator
{
member1 = other.member1;
}
}
what about move ctor and move assignment? Should I need to implement those as well?
First of all if p1 and p2 are pointers then you can just assign them.
In case move constructor is not present then copy constructor will be used instead.
It remains for me hard to understand what is the logical meaning of allowing assignment on something that has constant non-static parts.
What you have written is sufficient.
When no move constructor exists then the copy constructor will be used instead, and there's really no purpose in move semantics here.
Just remove const from that member if you really need assignment
I have some questions about constructors in C++. For each question (from (1) to (4)) I would like to know if the behaviour is perfectly defined regarding to the standard.
A) The first one is about initialization of members :
class Class
{
public:
Class()
: _x(0)
, _y(_x)
, _z(_y) // <- (1) Can I initialize a member with other members ?
{
;
}
protected:
int _x;
int _y;
int _z;
};
B) What are the functions added to each class by the compiler ?
template<typename T> class Class
{
public:
template<typename T0>
Class(const Class<T0>& other)
{
std::cout<<"My copy constructor"<<std::endl;
_x = other._x;
}
template<typename T0 = T>
Class (const T0 var = 0)
{
std::cout<<"My normal constructor"<<std::endl;
_x = var;
}
public:
T _x;
};
// (2) Are
// Class(const Class<T>& other)
// AND
// inline Class<T>& operator=(const Class<T>& other)
// the only functions automatically added by the compiler ?
As an example, if I call :
Class<int> a;
Class<int> b(a); // <- Will not write "My copy constructor"
Class<double> c(a); // <- Will write "My copy constructor"
(3) Is this behaviour perfectly normal according to the standard ?
(4) Do I have the guarantee that an empty constructor is not automatically added and that Class<int> x; will write "My normal constructor" ?
Can I initialize a member with other members ?
Yes, as long as those other members have already been initialised; i.e. as long as their declarations come before the member being initialised.
Are [the copy constructor] and [the copy-assignment operator] the only functions automatically added by the compiler ?
It will also implicitly declare a destructor, which will destroy _x using its destructor.
In C++11, a move constructor (Class(Class&&)) and move-assignment operator (Class& operator=(Class&&)) are also implicitly declared, unless you declare a copy or move constructor, or a copy or move assignment operator.
Note that your constructor template is not a copy constructor, and the implicit one will be used instead:
Class<T1> t1;
Class<T1>(t1); // prints nothing
Class<T2>(t1); // prints "My copy constructor" (which is a lie)
Is this behaviour perfectly normal according to the standard ?
Yes, see chapter 12.
Do I have the guarantee that an empty constructor is not automatically added and that Class<int> x; will write "My normal constructor" ?
Yes, a default constructor will only be implicitly declared if you don't declare any constructors at all.
What happens, in case of copy constructor, if I use pointer in the parameter instead of reference variable? for ex.
class MyClass
{
private: int a;
char *str;
public:...
...
MyClass(MyClass *pObj)
{
....
....
}
};
MyClass(MyClass *pObj)
Is not a Copy Constructor, it is an Overloaded Constructor.
The copy constructor takes reference to the same type as argument. Ex:
MyClass(MyClass &)
The compiler generates an copy constructor for your class implicitly if you do not provide your own version.
This copy constructor will be called when compiler needs to generate a copy of an object.
The overloaded constructor said above will only be called when you explicitly call it.
Code Sample:
#include<iostream>
class MyClass
{
private: int a;
char *str;
public:
MyClass(){}
MyClass(MyClass *pObj)
{
std::cout<<"\ninside *";
}
MyClass(MyClass &pObj)
{
std::cout<<"\ninside &";
}
void doSomething(MyClass obj)
{
std::cout<<"\ndoSomething";
}
};
int main()
{
MyClass ob,ob2;
MyClass obj2(&ob); //Explicitly invoke overloaded constructor
ob.doSomething(ob2); //Calls copy constructor to create temp copy of object
return 0;
}
Note the output is:
inside *
inside &
doSomething
By definition, a copy constructor is a constructor with a const reference parameter to the same class.
Any other constructor definition is not a "copy constructor", so it won't be invoked by the compiler when you write something like:
MyClass x = y;
or
MyClass x( y );
Copy constructor is supposed to make a copy from an object and not from pointer.
Why pass by Reference and not by value? Because if you don't do so, the copy constructor will go in creation of the copy of the argument and it will be an endless loop.
How can I create an operator function within a class that serves to typecast other types as an object of that class?
e.g.
class MyClass
{
// ...
// operator ??
// ...
}
int main()
{
MyClass obj;
int Somevar;
obj=(MyClass)Somevar; // class typecast
}
In general, is there an operator that allows this kind of typecast in exact syntax?
Just add a constructor that takes one argument:
class MyClass {
explicit MyClass(int x) { … }
};
called as:
MyClass x = static_cast<MyClass>(10); // or
MyClass y = MyClass(10); // or even
MyClass z(10);
This allows an explicit cast as in your example. (The C-style cast syntax is also supported but I won’t show it here because you should never use C-style casts. They are evil and unnecessary.)
Sometimes (but very rarely), an implicit cast is more appropriate (e.g. to convert from char* to std::string in assignments). In that case, remove the explicit qualifier in front of the constructor:
class MyClass {
MyClass(int x) { … }
};
Now an implicit conversion from int is possible:
MyClass a = 10;
However, this is usually not a good idea because implicit conversions are non-intuitive and error-prone so you should normally mark the constructor as explicit.
Define a constructor taking int argument.
But implicit conversions has some problems, so many that the language has the keyword explicit to prohibit them.
Mainly that's about overload resolution.
So, perhaps think twice before allowing the implicit conversion.
Cheers & hth.,
Provide non-explicit constructor with argument of wanted type:
class MyClass {
public:
MyClass( int x );
...
};
MyClass a = 42;
Note though: this is usually a bad idea.
You need to construct the object implicitly.
class MyClass
{
int x;
public:
MyClass(int X = 0):x(X){} //also serves a default constructor
}
int main()
{
MyClass obj = Somevar; // implicit type construction
}
why not use operator=() ?
class MyClass
{
public:
Myclass& operator=()(int i) {
//do what you want
return *this;
}
}
int main()
{
MyClass obj;
int Somevar;
obj = Somevar; // call operator=(somevar)
}