I was browsing some code I wrote for a school project, that at a closer inspection looked weird to me. I had a class similar to the one below:
class Foo {
public:
Foo(std::string s) : _s(s) {}
private:
std::string _s;
};
int main() {
std::string str = "Hiyo";
std::vector<Foo> f;
f.push_back(str); // Compiles. Weird to me though.
f.push_back(Foo(str)); // Predictably, this compiles as well.
return 0;
}
Why is the first call to push_back a valid statement, even though str is not a Foo?
Class Foo has a non-explicit ctor taking one argument of type std::string (i.e. Converting constructor), which means it could be implicitly casted from a std::string.
f.push_back(str); // implicit casting from std::string to Foo
f.push_back(Foo(str)); // explicit casting from std::string to Foo
Note if you make the ctor explicit, the implicit casting will be prohibited.
class Foo {
public:
explicit Foo(std::string s) : _s(s) {}
// ~~~~~~~~
private:
std::string _s;
};
and then
f.push_back(str); // invalid now
f.push_back(Foo(str)); // still valid
The first push back will automatically initialize a Foo object given a string object; through your initializer list.
(Expects a Foo object, gets a string: can a Foo object be initialized with a single string? Yes, its initializer list has single element and the object is initialized from that element).
For details, see e.g.:
http://en.cppreference.com/w/cpp/language/initializer_list
I think that in the first pushback it is automaticaly initializes Foo(str)
So its basicaly tha same!
Related
I want to know if there's a way to make the = operator trigger the constructor (or any method) of a class upon its declaration
let's say
class foo
{
public:
string variable="";
foo(string var)
{
this->variable=var;
}
foo(){}
void operator=(string var)
{
this->variable=var;
}
}
int main()
{
foo obj="new foo object";
}
When I run that, it says "error: conversion from 'const char[15]' to non-scalar type 'foo' requested"
But when I do this
foo obj;
obj="new foo object";
It works
What can I do so the first method will work?
What can I do so the first method will work?
Provide a constructor that takes an argument of type char const *.
And use the initialization list of the constructors to initialize members, not assignments in the constructors body.
BTW:
foo obj = "new foo object";
does NOT call operator=().
Why don't you just use the constructor (that should be declared as explicit anyway, so the construct you want is actually bad practice IIRC)?
Just do:
foo obj("bar");
Also variable should not have a default empty value, the default constructor will create it properly.
You should also put variable in the initializer list.
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 am getting no appropriate default constructor available error with the following simple piece of code:
class A
{
public:
const string cs ;
};
void main()
{
A a;
return;
}
If I remove the const from string then code compiles fine. I can not understand why the default constructor is not getting created by compiler? And what is the deal with const string member variable?
I am working on VS2008.
As mentioned in the comments, const variables cannot be left unitialized in C++. There are two ways you can initialize your variable. In both cases, the content of the string can never be modified (as this is what const means).
1) In the class declaration. This method is useful only if you always want this string to have the same value across all of your objects. It is very inflexible and if you find yourself using it you should probably declare the variable as static.
class A
{
const string cs = "value of cs";
};
2) assign it in the constructor, using constructor chaining. This is much more flexible and idiomatic.
class A
{
const string cs;
public:
A() : cs("value of cs")
{
}
};
Note that this can be used with arguments, eg
A(string s) : cs(s) //initializes cs to the value of s
Your error probably arises from the compiler trying to find the second option.
Since C++17 it is legal to have a const member with no initializer -- if that member has a default constructor which initializes itself. void main() is still incorrect though!
So here is some valid code:
#include <string>
struct A { const std::string cs; };
int main()
{
A a;
}
The string a.cs is an empty string which is const.
If using an older compiler you will have to give a redundant initializer for cs.
Gotw 80 includes the following example:
// Example 1
//
#include <string>
using namespace std;
class A
{
public:
A( const string& s ) { /* ... */ }
string f() { return "hello, world"; }
};
class B : public A
{
public:
B() : A( s = f() ) {}
private:
string s;
};
int main()
{
B b;
}
The article goes to discuss why the line s = f() is incorrect - due to object lifetimes and order of construction. The article states that at the time, the error wasn't picked up by the compiler.
However, ignoring the problems of order of intialisation and object lifetime, I don't see how s = f() in the parameter list of the constructor can be legal syntactically - it appears to be trying to initialise a member in the parameter list (or perhaps declaring a default value). Can anyone explain what this syntax is trying to do?
It looks like the intention was to call f() and assign the result to B::s. Afterward, the result of that assignment (which is s) would be used as actual parameter when calling the inherited A constructor.
It's syntactically valid. Replace s in that expression with some non-member variable, and g++ accepts it without issue. You might see similar syntax used more often with ordinary function calls instead of constructor calls.
Syntactically it's legal... when you have a base class with a constructor that takes arguments you can of course pass any expression as parameter:
strut A {
A(int) {}
};
struct B : A {
B() : A( any expression that returns an int ) {}
};
The problem is that when evaluating the expression in the example the object is not even yet a fully constructed A instance, so that code is invalid for two distinct reasons:
Calls a method of A of an non-instance (the constructor didn't start yet): f() call is illegal.
Assigns to a member that hasn't been initialized: s=... is illegal.
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.