Default initialize data members that are objects? - c++

Why do you have to initialize object data members in the constructor and you can't default initialize them like with primitive types? Is it possible to initialize them like with primitive types?
Here's an example:
class foo {
int a;
public:
foo(int _a) :a(_a) {};
};
class bar {
string a = "asdf";//no error
int num = 1;//no error
foo x(1); //error, why?
foo z;
public:
bar(): z(1){}//no error
};

In-class initializers only work with the operator= syntax or with brace-initializer lists, not with the function style initialization. So
foo x{1};
instead of
foo x(1);
should do the trick.
In your case, you could also use
foo x = 1;
but that would break if foo's constructor taking a single int was explicit.

Permitting direct-initialization in class-definition would lead to difficulties in distinguishing from function declarations:
Consider:
struct k;
struct foo { foo(int x = 1){} };
class toto
{
static constexpr int k = 1;
foo x(1); // hm might be ok...
foo y(); // hm ... NOK , what y is ? an object or a function declaration?!?!
foo z(k); // problem .... this seems a fucntion definition?!!!
foo z{k}; // clear it is not a function definition
};
The proper way to do this is either:
foo f= 1;
or
foo f{1};
or
foo f = {1};

Related

Assigning a class variable in class definition versus at class instantiation

What are the ramifications of assigning a class variable when defining the class versus in the class constructor? Is the variable assigned in the class definition accessible by all class instances?
Example of assignment at instantiation:
class Foo
{
private:
int x;
double y;
public:
Foo()
{
x = 0;
y = 1.;
}
};
Example of assignment in class definition:
class Foo
{
private:
int x = 0;
double y = 1.;
public:
Foo();
};
edit:
As to the class member being accessible by all instances, I think I was looking for the notion of a static declaration, I guess I'm just new to the curly brace languages.
In this code snippet
int x = 0;
double y = 1.;
there is no assignments. There are initializations.
In this code snippet
Foo()
{
x = 0;
y = 1.;
}
there is indeed used the assignment operator.
In general for objects of complex types it can be 1) impossible (either the default constructor or the assignment operator is not available) or 2) requiring many resources because at first default constructors are called that create the objects and after that there are called assignment operators.
It is desirable to define constructors at least like for example
Foo() : x( 0 ), y( 1 )
{
}
using mem-initializer lists.
Is the variable assigned in the class definition accessible by all class instances?
No!
The difference is that you default-initialize the member variables and then assign values to them in the first case. In the second case you value-initialize them - which is preferred. A third option, that also value-initializes them, is to use the member-initializer list:
class Foo
{
private:
int x;
double y;
public:
Foo() : x{0}, y{1.}
{
}
};

Passing functions as arguments not working inside a class

Creating a Foo object passing func to constructor works just fine in this example:
int func(int a) { return a; }
struct Foo {
Foo( int (*func_ptr)(int) ) {};
};
Foo bar(func);
However attempting to create a Foo object inside another class does not:
class ThisIsCrap {
Foo doesntWork(func);
};
How can I create a Foo object inside a class like I can outside a class? On the bit that doesn't compile, the error is: "cannot resolve type 'func'"
Thanks in advance.
You can provide an initializer for non-static class data members with a default member initializer (DMI):
int func(int a) { return a; }
struct Foo { Foo(int (*)(int)) {}; };
class ThisIsGreat {
Foo one_way = func; // DMI with copy-initialization syntax
Foo another_way{func}; // DMI with list-initialization syntax
};
Or of course you could use a constructor:
class ThisIsSane {
ThisIsSane()
: third_way(func) // constructor-initializer list
{}
Foo third_way;
};
Language-lawyer note for pedants: In C++11, ThisIsGreat is not an aggregate; in C++14 it is.
1,000 thanks to Kerrek SB.
class ThisWorks {
Foo* working;
ThisWorks() {
working = new Foo(func);
}
}

What method do you use to initialize member variables?

Suppose I have a class Foo, with a member variable that is a std::vector of floats, bar. I then create an instance of Foo, called foo. Let's say that I do not know the length of bar before the program runs, but at the point when foo's constructor is called, I know that it's length should be x.
There are three ways I can think of to initialize the length of bar, and I'm just wondering which of the three most people tend to use. I have ranked them in order of what I would consider to be "best practice", but I'm more curious about what method people "actually" use in practice. Sometimes I use methods which make the code clearer to follow, rather than necessarily following best practice...
bar is a private member, and I resize it during foo's constructor, e.g. Foo foo(x){bar.resize(x)};
bar is a private member, and I call foo.ResizeBar(x) which resizes bar internally, after creating foo.
bar is a public member, and I call foo.bar.resize(x), after creating foo.
Or, in code:
1.
class Foo
{
private:
std::vector<float> bar;
public:
Foo(int x)
{
bar.resize(x);
};
};
int main()
{
Foo foo(100);
return 0;
}
2.
class Foo
{
private:
std::vector<float> bar;
public:
Foo()
{
};
void ResizeBar(int x)
{
bar.resize(x);
};
};
int main()
{
Foo foo;
foo.ResizeBar(100);
return 0;
}
3.
class Foo
{
public:
std::vector<float> bar;
Foo()
{
};
};
int main()
{
Foo foo;
foo.bar.resize(100);
return 0;
}
The problem with all three of your methods is that you're needlessly invoking the default initializer for your vector, and then modifying the already initialized vector to suit your needs.
You should be invoking the correct initializer using the initializer list:
Foo::Foo(std::size_t x) : bar(x, 0) { }
The best method is not in the list of options you posted. The best method is to initialize bar using member initializer lists.
Foo::Foo(int x) : bar(x) {}

Calling a constructor with no parameters works, with a parameter doesn't. Why?

I have a class defined as follows:
class Foo {
private:
boolean feature;
public:
Foo(boolean feature) : feature(feature) {}
// ...
};
I'm trying to construct an instance, as a private property of another class:
class Bar {
private:
Foo foo(true);
// ...
};
This doesn't work. I get expected identifier before numeric constant on the line with the declaration. When I remove the parameter from Foo's constructor definition simply and ask for a Foo foo;, it works.
Why?
How do I define and declare an instance of Foo that takes a boolean parameter?
You can't use that initialisation syntax in a class member declaration; you can only initialise members with {} or =. The following should work (assuming support for C++11 or later):
Foo foo{true};
Foo foo = Foo(true);
The pre-C++11 way to do this is:
class Bar {
public:
Bar() : foo(true){} //initialization
private:
Foo foo; //no parameter
};
Bonus:
class Bar {
private:
Foo foo(); //<- This is a function declaration for a function
//named foo that takes no parameters returning a Foo.
//There is no Foo object declared here!
};

class Bar { operator Foo(); }

What does this style of operator overloading mean?
class Foo {
Foo(int a) { ... }
};
class Bar {
operator Foo() { return Foo(25); }
};
That is user-defined conversion function which converts an instance of Bar into Foo implicitly.
Bar bar;
Foo foo = bar; // bar implicitly converts into Foo.
It is as if you've written this:
Foo foo = Foo(25);
If you've such a conversion function, then you can call this:
void f(Foo foo); //a function which accepts Foo
f(bar); // bar implicitly converts into Foo.
So such implicit conversion may not be desirable sometime, as it might cause problem, producing unintended result. To avoid that, you can make the conversion function explicit as (in C++11 only):
//valid in C++11 only
class Bar {
explicit operator Foo() { return Foo(25); }
};
Now both of these would give error:
Foo foo = bar; //error
f(bar); //error
However, the following is allowed:
Foo foo = static_cast<Foo>(bar); //Ok
f(static_cast<Foo>(bar)); //Ok
It's an overload of the cast operator. Best documentation I could find was MSDN
Basically, if you have a Bar you can cast it to a Foo which is constructed with a specific value:
Bar b;
Foo f = b;