I have been looking for quite some time for my question, but I haven't found any satisfying answer yet.
The question is fairly easy: What should I put between the brackets when I use Implicit Assignment for an Object.
I was always used to seeing something like this: The assign an int, you give it an int-value
class Point2D
{
private:
int m_nX;
int m_nY;
public:
// A specific constructor
Point2D(int nX, int nY)
: m_nX(nX), m_nY(nY) // So the int m_nX gets the int-value nX
{
}
}
But recently I found a tutorial where PARAMETERS were given to an object. (http://www.learncpp.com/cpp-tutorial/102-composition/)
class PersonalComputer
{
private:
CPU m_cCPU;
Motherboard m_cMotherboard;
RAM m_cRAM;
public:
PersonalComputer::PersonalComputer(int nCPUSpeed, char *strMotherboardModel, int nRAMSize)
: m_cCPU(nCPUSpeed), m_cMotherboard(strMotherboardModel), m_cRAM(nRAMSize)
// So the m_cCPU-object is given a parameter nCPUSpeed, and not another m_cCPU-object
{
}
};
So my question is: How does Implicit Assignment work for objects? And how can I assign an Object with an Object itself (e.g. give an m_cCPU2-object to the m_cCPU-object).
Thanks
This is called initialization (not "implicit assignment").
For a primitive type it means that object is given that initial value
int nX(5);
For a class type it means to call the class's constructor with those arguments:
Motherboard m("ABCDE");
To assign an initialize an object with another object in the initializer list you want to define a copy constructor
class CPU
{
CPU(const CPU& other)
: someSpeedVariable(other.someSpeedVariable) // Eg.
{}
}
Then you can do this in other classes.
class PC
{
PC(const CPU& cpu)
:m_cpu(cpu)
{}
CPU m_cpu;
}
I think this is what you're asking?
Related
It's been a long time since I've seen C++ -- 30 years of more, and obviously, things have changed a lot. I'm also spoiled with Scala, Julia etc, which take care of this magic under the covers, but... no more.... I'm tryihng to figure out why this doesn't work:
class Foo {
uint_fast8_t val1;
std::string name;
uint_fast16_t val2;
};
std::map<std::string, Foo> myMap;
myMap["Test"] = { 1, "Test2", 2 };
This fails to compile because several operators need to be overloaded for map to work. Note, this happens evne with a constructor defined such as
Foo(uint_fast8_t v1, std::string s, uint_Fast16_t v2) { };
If I just do a
myMap["Test"] = Foo()
This works because the constructor has the expected number of arguments (0) as opposed to 3. It's probably basic, and I'm sure I'm showing how long it's been, but what did I miss?
All the members of a class are by default private in contrast to struct where all the members are by default public so default value initialization of the member variables in a class via list initializer is not allowed.
Kindly refer this link for better understanding.
Hope this helps you
You have a class with default constructor,which takes zero arguments.
And you are trying to create he inline object with passing the three arguments.
I will suggest to add the parameterized constructor.
class Point {
private:
int x, y;
public:
// Parameterized Constructor
Point(int x1, int y1)
{
x = x1;
y = y1;
}
...
};
// Constructor called
Point p1(10, 15);
Basic C++ constructor types can be checked at link
This question already has answers here:
What is this weird colon-member (" : ") syntax in the constructor?
(14 answers)
Closed 4 years ago.
What's the difference between these two declarations of constructors:
class Fruit {
private:
int price;
public:
Fruit(int x): price(x)
{
}
};
VS
class Fruit {
private:
int price;
public:
Fruit(int x)
{
price = x;
}
};
The first one I have seen in case of inheritance.
As per my knowledge, this is not a duplicate question. If you find one feel free to close this question.
The first one initialize price with x where the second one initialize price with its default value (default construct it; in case of a int variable, is initialized with an undefined value) and then copy x in price.
In other words, the first one is almost equivalent to
int price = x;
where the second one is almost equivalent to
int price;
price = x;
In case of a int variable (taking also in count the compiler's optimizations) I suppose there isn't an effective difference.
But when price is a complex object, with an heavy construction cost, there can be a great difference.
As better explain Peter, "It's not construction cost that makes the difference between the two for complex objects. It is a question of whether reassigning after default initialisation is more costly than initialising in one step. Practically, the two stage process is often more expensive (by various measures) than direct initialisation, since it can be necessary to clean up the default setting in order to change the value. There are also concerns of exception safety - what if reassignment or construction throws an exception."
So, usually, is strongly suggested to use the first solution (initialize the object with the right value).
See also the Zereges's answer that point the attention over the fact that the first one method is the only available to assign a value to a constant member.
Indeed you can't write
int const price;
price = x; // error: price is const
The first one uses an initialization list, while the other doesn't, and assigns x to the data member price inside the body of the constructor.
We usually prefer to use initialization lists, and to keep the body of the constructor as simple as possible.
To add up to other answers, the first option is the natural way to initialize const members
struct C
{
const int val;
C() : val(5) // Perfectly OK
{
}
C(int) // error: uninitialized const member in 'const int' [-fpermissive]
{
val = 5 // error: assignment of read-only member 'C::val'
}
};
Also, when class has members of type, that are not default-constructible, this is the way to initialize them
struct D
{
struct not_default_constructible
{
not_default_constructible(int)
{
}
} var;
int& ref;
D(int a) : ref(a), var(5) // Legal
{
}
D(int a, char) // error: uninitialized reference member in 'int&' [-fpermissive]
{ // error: no matching function for call to 'D::not_default_constructible::not_default_constructible()'
ref = a;
}
};
The second one does not initialize price with x when a Fruit is created which therefor default constructs it. Just as if you'd written:
class Fruit{
private :
int price
public:
Fruit(int x) :
price() // default constructed
{
price = x
}
}
For effectiveness, it's better to initialize with the value you want to assign to it.
I am coming from the Java background. I have the following program.
#include <string>
#include <iostream>
class First {
public:
First(int someVal): a(someVal) {
}
int a;
};
class Second {
public:
First first;
Second() { // The other option would be to add default value as ": first(0)"
first = First(123);
}
};
int main()
{
Second second;
std::cout << "hello" << second.first.a << std::endl;
}
In class Second, I wanted to variable first to remain uninitialized until I specifically initialize it in Second()'s constructor. Is there a way to do it? Or am I just left with 2 options?:
Provide a parameter-less constructor.
Initialize it with some default value and later re-assign the required value.
I can't initialize first in the initializer-list with the right value, since the value is obtained after some operation. So, the actual required value for first is available in Second() constructor only.
MY suggestion: Use a function:
private: static int calculate_first(int input) {return input*5;}
explicit Second(int input) : first(calculate_first(input)) {}
Base classes will be initialized in the order they're declared in the class inheritance list, and then members will be initialized in the order that they're listed in the class, so the calculation can depend on non-static member-variables and base classes if they have already been initialized.
Alternatively:
Default constructor, then reassign:
explicit Second(int input) { first = input*5; }
Dummy value, then reassign:
explicit Second(int input) : first(0) { first = input*5; }
Use boost::optional (or std::optional as of C++17):
boost::optional<First> first;
explicit Second(int input) { first = input*5; }
Use the heap:
std::unique_ptr<First> first;
explicit Second(int input) { first.reset(new First(input*5));}
Second(const Second& r) first(new First(*(r->first))) {}
Second& operator=(const Second& r) {first.reset(new First(*(r->first)));}
Placement new:
This is tricky and not suggested
and worse in every way than boost::optional
So sample deliberately missing.
But it is an option.
Initialize first in the member initializer list.
It may help to perform your calculations in a helper function and use a forwarding constructor:
class Second {
public:
Second() : Second(helper_function()) {}
private:
Second(int calc): first(calc) {}
static int helper_function() { return ...; }
First first;
};
This sentence is the core of the problem:
I can't initialize first in the initializer-list with the right value,
since the value is obtained after some operation.
You should know that what you want to do here is not perfect programming style in Java, either. Leaving the field with some default value and then assigning it a bit later after some calculations have been done effectively prevents it from being final, and consequently the class from being immutable.
In any case, your goal must be to push those calculations directly into the initialization of the member, using private helper functions (which may be static):
class Second {
private:
First first;
static int getInitializationData()
{
// complicated calculations go here...
return result_of_calculations;
}
public:
Second() : first(getInitializationData()) {}
};
In my opinion, everything else is just a workaround and will complicate your life in the long run.
You can just do what you said in the comments, or, you can make first a pointer to First and give it memory whenever you like, although i don't recommend this way
One way to separate object lifetimes is to use the heap, make first a pointer and initialize it anytime you like:
class Second {
public:
First* first;
Second() {
first = new First(123);
}
};
of course, you'll probably want to use a smart pointer of some sort rather than a raw pointer.
If you don't code to explicitly initialize a member variable, the default initializer is used to initialize it.
The draft C++ standard has the following about initialization of base classes and member variables:
12.6 Initialization [class.init]
1 When no initializer is specified for an object of (possibly cv-qualified) class type (or array thereof), or the initializer has the form (), the object is initialized as specified in 8.5.
And
12.6.1 Explicit initialization [class.expl.init]
1 An object of class type can be initialized with a parenthesized expression-list, where the expression-list is construed as an argument list for a constructor that is called to initialize the object. Alternatively, a single assignment-expression can be specified as an initializer using the = form of initialization. Either direct-initialization semantics or copy-initialization semantics apply; see 8.5.
I want to know what's difference in the following two class.
example 1:
class A
{
string name;
public:
A(const char* _name):name(_name){}
void print(){cout<<"A's name:"<<name<<endl;}
};
example 2:
class A
{
string name;
public:
A(const char* _name){name(_name);}
void print(){cout<<"A's name:"<<name<<endl;}}
why the example 1 is passed and the last one is wrong?
Thanks
In example 1 you initialize the string with the given value right away.
In example 2 you create an empty string first and assign it later on.
Despite some performance differences and ignoring possible differences due to copy constructor handling etc. it's essentially the same result.
However once you use a const member you'll have to use example 1's way to do it, e.g. I usually create unique IDs the following way:
class SomeObject
{
static unsigned int nextID = 0;
const unsigned int ID;
SomeObject() : ID(nextID++)
{
// you can't change ID here anymore due to it being const
}
}
The first example is an actual initialization. It has a number of advantages, including being the only way to set up const members, and having proper exception-safety.
The second example is not valid C++, AFAIK. If you had instead written name = name_, then this would just be normal assignment. Of course, this isn't always possible; the object might be const, or not have an assignment operator defined. This approach could also be less efficient that the first example, because the object is both default-initialized and assigned.
As for why the initializer list is before the constructor body; well, that's just the way the language has been defined.
That's just how the language is defined. The member initializers should be placed before the body of the constructor.
In the first example the member name is initialized with a ctr getting char * as parameter.
In the second case it is initialized with a default ctr at first and it gets value by the assignment operator (operator=) later. That's why it is wrong with your case that it is already constructed there so you can not use the ctr once again you could just use the assignment operator.
The reason is that name lookup works different in initializer lists and function bodies:
class A
{
std::string foo; // member name
public:
A(const char* foo) // argument name
: foo(foo) // member foo, followed by argument foo.
{
std::cout << foo; // argument foo.
}
};
If the initializer list was inside the function body, there would be an ambiguity between member foo and argument foo.
The motivation behind the initialization list is due to const field holding a object by value (as opposed to reference/pointer field).
Such fields must be initialized exactly once (due to their const-ness). If C++ didn't have initialization list then a ctor would look something like:
class A {
public:
const string s;
const string t;
A() {
// Access to either s or t is not allowed - they weren't initialized
s = "some-string";
// now you can access s but you can't access t
f(*this);
t = "some other string";
// From now you can access both ...
}
}
void f(A& a) {
// Can you access a.s or a.t?
cout << a.s << a.t;
}
Without an initialization list a ctor can pass a partially-initialized object of type A to a function, and that function will have no way of knowing which fields are initialized yet. Too risky and very difficult for the compiler/linker to check.
I've been programming in C++ a while and I've used both methods:
class Stuff {
public:
Stuff( int nr ) : n( nr ) { }
private:
int n;
}
Or
class Stuff {
public:
Stuff( int nr ) {
n = nr;
}
private:
int n;
}
Note: This is not the same as this, similar but not the same.
What is considered best practice?
Initializer lists are preferred. See FAQ 10.6
One big advantage to using initializers: If an exception is thrown anywhere within the initializer list, the destructors will be called for those members that had already been initialized -- and only for those members.
When you use the contructor body to initialize the object, it's up to you to handle exceptions properly and unwind the object as appropriate. This is usually much harder to get right.
Use the initializer list when possible. For an int, it doesn't matter much either way, but for a more complex member object, you'd end up with the default constructor of the object being called, followed by an assignment to that object, which is likely to end up being slower.
Plus, you have to do it that way anyway for const members or members which don't have a default constructor.
If possible, use the first version.
The first is initializing using intializer lists, and actually calls the constructors of the members.
The second is assignment. If n was of a type with a default constructor, it the would have already been called, and then you'd be assigning to it. If n didn't have a default constructor, you'd be forced to use the first type. Likewise if n was a reference: int &n.
If there are no constructors of you members that directly take one of the parameters to your constructor, it may be worthwhile to add private static functions that can do the conversion for you.
I generally try to do the initializer list when I can. For one thing, this makes it explicit that you are initializing code in the constructor. const memebers have to be initialized this way.
If you just put code in the constructor's body, it is quite possible someone may decide to come along and move a big chunk of it into a non-constructor "setup" routine later.
It can be taken overboard though. I have a coworker who likes to create classes that have 2 pages of initilizer code, no constructor code, and perhaps 2 pages for the entire rest of the class' code. I find that really tough to read.
I want to add that you don't need to declare the initializer list on the Header (.h). It can be done at the implementation of the constructor (which is very common).
So then:
//Stuff.h
class Stuff {
public:
Stuff( int nr );
private:
int n;
}
//Stuff.cpp
Stuff::Stuff(int nr)
: n(nr)
{
//initalize complex members
}
is legal and imo concentrates the initialization of fields where it matters. Sometimes we need to initialize complex members in the body, so you have your initializer list and the complex initialization all in the .cpp file.
The second option is not initialization but assignment. With types that have user defined default constructors, the second option will call the default constructor and later on call the assignment operator (whether user defined or not) to assign the value.
Some types cannot be default initialized: If you have an attribute without default constructor, hold references (constant or not) or have constant attributes they must be initialized in the initializer list.
Arrays can be value-initialized in the initialization list, but not in the constructor body:
class X {
public:
X() : array() {} // value-initializes the array
// equivalent to:
// X() { for ( int i = 0; i < 10; ++i ) array[i]=0; }
private:
int array[10];
};
For POD types, you can value-initialize them in the initialization list but not inside the brackets:
class X {
public:
X() : pod() {} // value-initializes
// equivalent to (but easier to read and subtly faster as it avoids the copy):
// X() { pod = {}; }
private:
PODType pod;
};
Finally, some classes offer functionality through the use of constructors that will be more complex (if achievable) after default construction.
class X
{
public:
X() : v(10) {} // construct a vector of 10 default initialized integers
// equivalent to:
// X() { for ( int i = 0; i < 10; ++i ) v.push_back(0); }
private:
std::vector<int> v;
};
Last, whenever they are in fact equivalent, initialization lists are more idiomatic in C++.