After studying the member copying and the assignment operator in C++,
and looking at " member copying of class " which explains the conditions where default assignment operator cannot be generated. I am not very clear about the concepts as the following example I tried actually works on g++4.5
#include<iostream>
using namespace std;
class Y{
int& x;
const int cx;
public:
Y(int v1,int v2)
:x(v1),cx(v2)
{}
int getx(){return x;}
int getcx(){return cx;}
};
int main()
{
int a = 10;
Y y1(a,a);
Y y2 = y1;//assignment
cout<<y1.getx()<<" "<<y1.getcx();
return 0;
}
So where am I not getting the concepts. Please suggest other examples (if possible) so that I can understand better.
Y y2 = y1; is not an assignment. It's a copy constructor call. If you declare and initialize a variable on the same line, a one parameter constructor is called with the right hand side of the equals sign as the parameter. There's nothing about Y that prevents the default copy constructor from being instantiated (and called).
Try the following:
Y y1(10, 10);
Y y2(11, 11);
y2 = y1;
This should fail, although I can't test it right now.
class Y{
int& x;
public:
Y(int v1,int v2)
:x(v1),cx(v2)
{} // v1 ceases to exist from this point
};
x is a reference variable to an int. Now you are initializing it to v1, which means x is an alias to v1 itself. The scope of v1 is in the constructor alone. With that said -
Y y2 = y1;//assignment => Not assignment. It is initialization.
is equivalent to
Y y2(y1); // compiler is looking for the overloaded constructor ( ie. copy constructor in this case ).
class Y{
public:
Y ( const Y & other ); // copy constructor
// ...
};
#include<iostream>
using namespace std;
class Y{
int& x;
const int cx;
public:
Y(int v1,int v2)
:x(v1),cx(v2)
{}
int getx(){return x;}
int getcx(){return cx;}
};
int main()
{
int a = 10;
Y y1(a,a);
Y y2 = y1;//NOT assignment. Object is yet to be constructed, so calls copy c'tor
y2 = y1; // assignment operator is called
cout<<y1.getx()<<" "<<y1.getcx();
return 0;
}
/*
D:\Workspaces\CodeBlocks\Test\main.cpp||In member function 'Y& Y::operator=(const Y&)':|
D:\Workspaces\CodeBlocks\Test\main.cpp|4|error: non-static reference member 'int& Y::x', can't use default assignment operator|
D:\Workspaces\CodeBlocks\Test\main.cpp|4|error: non-static const member 'const int Y::cx', can't use default assignment operator|
D:\Workspaces\CodeBlocks\Test\main.cpp||In function 'int main()':|
D:\Workspaces\CodeBlocks\Test\main.cpp|20|note: synthesized method 'Y& Y::operator=(const Y&)' first required here |
||=== Build finished: 3 errors, 0 warnings ===|
*/
Your class contains members which cannot be default-constructed or assigned, namely:
References
Constants
Therefore, no default constructor or assignment operator can be implied for your class. For example, you have to write your own constructor:
class Foo
{
const int a;
int & b;
public:
Foo(int val, int & modify_me) :
a(val) , // initialize the constant
b(modify_me) // bind the reference
{ }
};
It is clear that you cannot default-construct Foo (i.e. Foo x;). It is also clear that you cannot reassign objects of class Foo (i.e. x = y;), because you cannot reassign references or constants.
By giving your class a reference or a constant member, you actually confer reference or constant semantics on the class itself, if you will, so this should be a fairly immediate logical consequence. For example, reassignment probably doesn't even make sense semantically, because your class is supposed to embody a constant concept.
However, note that you can make copies of your class: That's because you can make "copies" of references (i.e. furhter aliases), and copies of constants. Therefore, a copy constructor is available implicitly, by simply applying copy-construction member-by member. So you can say:
int n;
Foo x(15, n);
Foo y(x);
Foo z = x; // these two are identical!
This results in two further objects y and z which have y.a == 15 and z.a == 15, and y.b and z.b are all references to n. (Don't be confused by the two alternative syntaxes at the end; both invoke the copy constructor.)
Related
C++ has a nice new feature:
struct Point{
int x;
int y;
int z;
};
Point p{.x=47, .y=1701, .z=0};
But if I add a constructor then I am forbidden from using the nice designated initalizers syntax:
struct Point{
Point(int x, int y, int z = 0): x(x), y(y), z(z){}
int x;
int y;
int z;
};
static Point p{.x=47, .y=1701, .z = 0};
error: designated initializers cannot be used with a non-aggregate
type 'Point'
Am I missing something obvious(why it would be terrible if designated initalizers worked with structs/classes that have public members, but are not aggregates) or this is just a missing feature that is just not added to the standard?
Aggregate initialization (including initialization with designed initializers) circumvents the constructor of the class.
This is not a problem for aggregates, since they aren't allowed to have user-defined constructors. But if you allow this kind of initialization for classes with user-provided constructors (that do something useful), it can be harmful.
Consider this example:
class A
{
static std::map<A *, int> &Indices()
{
static std::map<A *, int> ret;
return ret;
}
public:
int dummy = 0;
A(int index)
{
Indices().emplace(this, index);
}
A(const A &) = delete;
A &operator=(const A &) = delete;
~A()
{
auto it = Indices().find(this);
std::cout << "Deleting #" << it->second << '\n';
Indices().erase(it);
}
};
If you were able to do A{.dummy = 42};, you'd get UB in the destructor, and would have no way to protect against this kind of usage.
Designated initalizers where a feature lifted from C. Most C++ compilers are also C compilers, and it was a C feature first.
They added a restriction (that the initializers be in order) and applied it to C++ types that matched C types, and got it into C++. Most major C++ compilers already had it as a C++ extension (without the restriction); the restriction was checked with the compiler implementors as being reasonable, and then the "cost" of adding the feature was really low.
Once you have a constructor, it becomes a larger language issue. Does the initializer refer to the constructor arguments? If yes, we run into the problem that argument names are not unique. If no, then how do we handle it when the constructor sets a value and the initializer set a different value?
Basically we need function-arguments-by-name to get sensible designated initializers with constructors. And that is a new feature, not one simply lifted from C.
The workaround (for named arguments) is:
struct RawPoint{
int x = 0;
int y = 0;
int z = 0;
};
struct Point {
Point( int x_, int y_, int z_ = 0 ):
x(x_), y(y_), z(z_)
{}
explicit Point( RawPoint pt ):
Point( pt.x, pt.y, pt.z )
{}
int x, y, z;
};
then you can do:
Point pt( {.x=3} );
by accessing the RawPoint's designated initializer feature.
This is the same way you can have designated initializers in function calls.
This also works:
struct Point:RawPoint {
Point( int x, int y, int z = 0 ):
RawPoint{x,y,z}
{}
explicit Point( RawPoint pt ):
RawPoint( pt )
{}
};
I have two classes one of them has an object of another class as a data member and it's constructor accepts the class object to initialize the data member object.
class x{
public:
x(int a, int b)
{ cout << a << b;}
};
class y{
x temp;
y(x& o){ this-> temp = o;}
};
But compiler shows an error in y::y(x&): no matching function to call x::x()
I am using codeblocks 16.01
You have defined the constructor:
x(int a, int b)
in x. This means that the compiler will no longer define any constructors for you, this includes the x() constructor. So you can only construct x with x(int, int). Here in your code:
x temp;
y(x& o) { // < No initializer list
You attempt to default construct x, but x has no default constructor! Either define one, or construct x in the initializer list with the constructor you have provided.
For example:
y(x& o) : x(0, 0) {
But you will create your object then you will use the implicitly defined copy-assignment operator to assign it, which is a bit of a waste of time. You can actually solve all these problems by using the copy-constructor:
class x{
...
x(const x ©) { // Define a copy constructor or just use
// the implicitly defined one.
Then in y, just use it in y's initializater list:
x temp;
y(x& o) : temp(o) {}
y(x& o){ this-> temp = o; }
is not very C++ idiomatic.
I. As a rule, you should avoid requiring more access rights than needed. Here, you're likely to not mutate the construction argument, so you don't need to pass it by a mutable reference:
y(x const &o);
II. Member initialization is done very differently in C++:
y(x const &o): temp(o) {}
When you write
y(x const &o) { temp = o; } // please avoid writing `this->'
then what happens is: first, temp is constructed and default-initialized (prior to the opening brace); then, inside the braces, temp is already a valid object, so what follows is a copy-assignment. In your case, x is not default-constructible, so compilation fails.
I want to re-define [] operator for a vector. I thought the simplest way to achieve this is to create my own class, say something like this (this is a simplified example):
class MyVec
{
private:
std::vector<double> x; // I don't need a copy in here, it could be a reference
public:
MyVec(const std::vector<double>& y) { x = y; }
double operator[](int i) { return x[i-1]; }
};
Now the problem is that I basically do not need to copy data to x, I could store a reference to it, but as far as I know, I cannot use uninitialized references in class. Nonetheless, maybe there is some kind of workaround for this to work without copying the data?
class construction does not allow for this
It does, you just need to use the member initializer list. Using it is the recommended way of initializing class members from the constructor - you should not use the constructor body for that.
class MyVec
{
private:
const std::vector<double>& x;
public:
MyVec(const std::vector<double>& y) : x{y} { }
double operator[](int i) { return x[i-1]; }
};
wandbox example
Note that if you take a const& in the constructor, you need to store a const&, otherwise you lose the const-ness of passed constructor argument.
For the implmentation of the constructor like MyVec(const std::vector<double>& y) { x = y; }, member x will be default constructed and then assigned by y in the constructor's body. But reference members can't be default constructed.
So if you declare the member as reference you have to initialize them by member initializer list:
For members that cannot be default-initialized, such as members of reference and const-qualified types, member initializers must be specified.
e.g.
class MyVec
{
private:
const std::vector<double>& x; // it's a reference (to const)
public:
MyVec(const std::vector<double>& y) : x(y) {}
double operator[](int i) { return x[i-1]; }
};
Note that for this case the member has to be declared as reference to const, because the parameter type of the constructor is reference to const.
What is the difference between this two constructor?
int x, y; //position
BasePoint(int px, int py) : x(px), y(py) {}
and
int x, y; //position
BasePoint(int px, int py)
{
x = px;
y = py;
}
What is x(px), y(py) called? And When do I use this type of variable initialization?
Thanks.
First one is doing initialization using initialization-list, and second one is doing assignment using assignment operator.
First one is recommended!
BasePoint(int px, int py) : x(px), y(py) {}
^^^^^^^^^^^^^ this is called initialization-list!
Read this FAQ : Should my constructors use "initialization lists" or "assignment"?
The FAQ answer starts with :
Initialization lists. In fact,
constructors should initialize as a
rule all member objects in the
initialization list. One exception is
discussed further down [...]
Read the complete answer.
What is x(px), y(py) called?
These are called initializer lists. What you are actually doing is copying the value of px to x and py to y.
Uses:
class foo
{
private:
int numOne ;
public:
foo(int x):numOne(x){}
};
class bar : public foo
{
private:
int numTwo;
public:
bar(int numTwo): foo( numTwo ), // 1
numTwo(numTwo) // 2
{}
};
bar obj(10);
1. Notice that derived constructor's argument can be passed to base class constructor.
2. Compiler can resolve, in this case, which one is argument and which one is member variable. Had if, this needs to be done in the constructor,then -
bar::bar(int numTwo) : foo( numTwo)
{
this->numTwo = numTwo; // `this` needs to be used. And the operation is called assignment. There is difference between initialization and assignment.
}
BasePoint(int px, int py) : x(px), y(py) {}
here u are using the initialization list
so the object when constructed will not go inside the body and initiate those values.it saves time by not entering in the body of the constructor
Another use of this is when calling the derived class constructor.
where if you use the statement like
new derivedclass(a,b,c)
and you can write this
derivedclass(int x,int y,int z):baseclass(a,b),h(z){}
I know that default constructors initialize objects to their default values, but how do we view these values? If there's a variable of type int, it is supposed to be initialized to 0. But how do we actually view these default values of the constructors? Can anyone please provide a code snippet to demonstrate the same?
Unless specified otherwise, objects are constructed with their default constructor, only if one is available.
And for example ints are not initialized.
This is a common source of huge troubles and bugs, because it can have any value.
So the rule is , always initialise your variables, and for a class you do it in the initialization list
class A
{
private:
int i;
float f;
char * pC;
MyObjectType myObject;
public:
A() : // the initialisation list is after the :
i(0),
f(2.5),
pC(NULL),
myObject("parameter_for_special_constructor")
{}
}
}
In C++, int is not a class and does not have a default (or any other) constructor.
An int is not guaranteed to be initialised to 0.
If you have a class that has an int as an attribute, you should explicitly initialise it in each of the class's constructors (not just the default one).
class sample
{
private:
int x;
public:
sample()
:x(0)
{
}
sample(const int n)
:x(n)
{
}
sample(const sample& other)
:x(other.x)
{
}
// [...]
};
This way you (and users of your class) can "view" the default values.
Good coding practice: write your own constructor, so you know how it will be initialized. This is portable and guaranteed to always have the same behaviour. Your code will be easier to read and the compiler knows how to make that efficient, especially when using the special notation:
class Foo
{
public:
Foo() : i(0), j(0) {}
private:
int i;
int j;
};
AFAIK, if T is a type (not necessarily a class), T() returns a default value for the type T. Here's a small test I ran:
int main()
{
char c = char();
int i = int();
cout << "c = " << hex << (int) c << endl;
cout << "i = " << i << endl;
}
The output is:
c = 0
i = 0
Default constructors do not automatically initialise ints to 0. You can use parentheses to indicate the default value though.
struct X
{
int x;
};
struct X x1; // x1.x is not necessarily 0
struct Y
{
int y;
Y() : y()
{
}
};
struct Y y1; // y1.y will be 0
show your code
And if your int value is a member of class .
you must give it a value in your default constructor func
The default constructor is which can be invoked with 0 parameters. For example
struct X
{
X(int x = 3) //default constructor
{
//...
}
};
It initializes the object to whichever state you code it to initialize. However, if you don't define any constructor at all the compiler will attempt to generate a default constructor for you - which, in turn is equivalent to a constructor with no arguments and no body. That means that all the members of class/struct type will be initialized with their def. ctors and all the members of primitive types like int will remain uninitialized. Please note that I specialy noted that the compiler will attempt to generate a dflt ctor, because it can fail to do so, for example when one or more members of the class do not have default constructors. HTH
AS soon as you have created an object start printing the values such as ob.x.
Thats the only way u can know what default constructor has assigned to the variables.