I recall I used to be able to do this and have it work as intended:
class foobar
{
public:
foobar(int x, int y)
{
x = x; //the variables x, y belonging to the class got correctly initialized
y = y;
}
private:
int x, y;
};
The above worked in circa 200x on Microsoft Visual C++ 6.0 and some later versions, I believe.
But now I have to do this on Microsoft Studio 2013 and I have to use this->, as such:
class foobar
{
public:
foobar(int x, int y)
{
this->x = x; //the other way no longer initializes class vars
this->y = y;
}
private:
int x, y;
};
Was there a language spec change or Microsoft compiler change?
Perhaps you are thinking instead of initializer list syntax, which would be unambiguous and should work correctly on any (non-buggy) C++ compiler:
foobar(int x, int y) : x(x), y(y) { }
In this case, the x and y before the parens are unambiguously data members, because that's the only thing that can go there (besides constructors for parent types). Inside the parens, the x and y refer to the constructor arguments that shadow the data members.
I can't think of any circumstance under which x = x; would do anything other than no-op self-assignment (buggy user-defined assignment operator overloads aside). If this worked in a prior VC++ version then it would have been a VC++ compiler bug. More likely, you used to use initializer list syntax (which does work) and forgot that's what you did.
Or this.
class foobar {
public:
foobar(int x, int y) : x(x), y(y)
{
}
private:
int x, y;
};
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 )
{}
};
This question already has answers here:
What is this weird colon-member (" : ") syntax in the constructor?
(14 answers)
Closed 5 years ago.
I saw this piece of code
class Foo {
public:
int x;
double y;
float z;
Foo(int x, double y, float z)
// XXX: What are the following doing?
: x(x),
y(y),
z(z) {}
}
I'm guessing what was written after the : is assigning the values to the members (x, y, z ) from the arguments.
Question 1: Why that way and not the following?
Foo(int x, double y, float z) {
this->x = x;
this->y = y;
this->z = z;
}
Question 2: in the original style, how does the compiler distinguish the member x from the parameter x? (In my modified pice of code, the qualifier this was used for that purpose)
For example, if I were to write this:
Foo(int x, double y, float z)
// XXX: What are the following doing?
: x(x * 2),
y(x * 3 + y ), // which 'x' is the 'x' in 'x * 2'?
z(z) {}
}
You guess correctly. Those are member initializer lists. The reason this is preferred over directly assigning in the constructor is because it is necessary for const class members, classes with no default constructors, and reference variables. Example:
class A
{
int b;
public:
A(int c) : b(c) {}; // No default constructor
};
class Test
{
A a; // A class with no default constructor
const int x; // A constant
int& r; // A reference
public:
Test(int d) : a(5), x(2), r(d) {};
};
int main()
{
Test test;
}
In this example, both members a and x of class Test cannot be assigned to because the first has no default constructor, while the latter is constant, meaning assignment to it would create an error. Finally, since reference variables cannot be assigned to, an initializer list is needed.
In the end, the primary difference comes down to the fact that initializer lists initialize the variable (who knew?), while assignment in the constructor is done after those member variables' constructors have been called.
As for your second question, you can see for yourself that the parameters are picked before the member variables during the initialization.
I have come up with a problem that I am unable to explain in light of my knowledge of C++.
I have a class that takes a constant reference to a struct of type X but when I pass an argument of type X (which i previously initialized) I get an error from the compiler saying it can't convert to the first member of a member of X. This doesn't make any sense to me.
The error is similar in clang and g++ which leads me to think I am missing something egregious.
error: no viable conversion from 'const Foo::X' to 'Foo::FooTypes'
Why is it trying to convert from X to FooTypes which is the first member of Z?
class Foo {
public:
enum FooTypes {
JPEG
};
struct Z {
FooTypes type;
int a;
};
struct X {
Z caps;
double host_address;
};
Foo(const X& x);
private:
const X x;
};
Foo::Foo(const Foo::X& x) :
x{x} {
}
int main() {
Foo::X new_x = {
{Foo::JPEG, 1}, 1.58 };
Foo *s = new Foo(new_x);
delete s;
return 0;
}
You should use round brackets instead of curly brackets:
...
const X m_x;
};
Foo::Foo(const Foo::X& x) :
m_x(x) {
}
...
here is list initialization:
...
m_x{x.caps, x.host_address}
...
Edit
#PauloNeves
I just found Bjarne Stroustrup's document http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2640.pdf, which contains next definition:
The general idea of "initializer lists" (as discussed for many years
in EWG) is to allow the use of a brace-enclosed list of expressions in
all contexts that allow initializers. The following list is lifted
from N2532:
Variable initialization; e.g., X x {v};
Initialization of a temporary; e.g, X{v}
Explicit type conversion; e.g. x X{v};
Free store allocation; e.g. p new X{v}
Return value; e.g., X f(){ /* ... */ return {v}; }
Argument passing; e.g., void f(X); /* ... */ f({v});
Base initialization; e.g., Y::Y(v) : X{v} { /* ... */ };
Member initialization; e.g., Y::Y(v) : mx{v} { X mx; /* ... */ };
I think that described Member initialization is your case. So as for me it looks like g++4.9 defect.
I am writing a simple program to calculate the area, the error that i am getting is :
no matching function for call to 'myclass::myclass()'
I am unable to understand the reason for this error and how to resolve it.
#include <iostream>
using namespace std;
class myclass{
int length;
int breadth;
public:
myclass(int x, int y);
int area(int x, int y);
};
myclass::myclass(int x,int y ){
length=x;
breadth=y;
}
int myclass::area(int x, int y){
return x*y;
}
int main()
{
myclass a;
a.area(3,4);
}
In this statement
myclass a;
there shall be called the default constructor of the class but you did not define the default constructor.
Also member function area has no a greate sense because it does not calculate the area of an object of the class.
The valid code could look as
#include <iostream>
class myclass
{
private:
int length;
int breadth;
public:
myclass(int x, int y);
int area() const;
};
myclass::myclass(int x,int y ) : length( x ), breadth( y )
{
}
int myclass::area() const
{
return length * breadth;
}
int main()
{
myclass a(3,4);
std::cout << "area = " << a.area() << std::endl;
}
Also you could declare the constructor the following way
myclass( int x = 0, int y = 0 );
In this case it would be a default constructor.
You have defined a constructor, which means the compiler is required not to define any constructors for you, including the default one. If you're using C++11, you can add this:
myclass() = default;
If not:
myclass() : length(0), breadth(0) {}
To the class declaration/body.
The error is because there is no default constructor and you are trying to call it. Since you have written your own constructor, you have overwritten the default constructor. One suggestion is to always write a default constructor or in your case, make sure you don't call default constructor.
Change the code in this way:
#include <iostream>
using namespace std;
class myclass{
int length;
int breadth;
public:
myclass(int x, int y);
int area(int x, int y);
};
myclass::myclass(int x,int y ){
length=x;
breadth=y;
}
int myclass::area(){
return length*breadth;
}
int main()
{
myclass a(3,4);
a.area();
}
You have defined a constructor for your class. This means that the compiler will not generate a default constructor, even though you're trying to call it inside main. There are two solutions:
Remove the custom constructor from your class:
myclass(int x, int y);
BUT, most likely you need that constructor, so simply instantiate the class using the parameters in the constructor you created, like this:
int main()
{
myclass a;
a.area(3,4);
}
EDIT:
My mind slipped a bit, there's a third solution. Use BOTH constructors. This would be the optimal solution if you think you will need to instantiate the class without any values assigned to the private elements:
public:
myclass();
myclass(int x, int y);
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){}