calling the default constructor
The second one is declaring a function a() that returns a base object. :-)
Why is this attempting to call the default constructor?
how can I produce the intended behavior (construct member after other initialization code in the constructor)?
This is not possible. In C++, all the object's base classes and non-static member variables must be constructed before the body of the constructor is entered.
In your code you wrote the opening {
of the Two
constructor without having previously offered any constructor arguments for the member variable, so the member variable is default-constructed.
If you have some logic to work out the initializer for one
then I would recommend putting that into a function:
int f() { /* logic here */ return 0; }
// ...
Two(): one( f() ) {}
Of course you could also add a default constructor to One
plus a means of assigning to it later.
when are constructors called and how to not call them
This happens because your B
class contains a member of type A
. As part of the construction of B
, the B::object
member is constructed, which requires a call to the A
constructor. So you actually have two A
instances: object
and bObject.object
.
Because you did not put object
in B::B()
's initializer list, B::object
is default-constructed. object = aObject;
then assigns to the existing A
stored in object
. So rather than copy-constructing B::object
, you default-construct it (which is responsible for the second "hello" you see) and then you assign a new value to it.
The compiler will provide a copy-constructor A(const A &)
for you, so you can copy-construct B::object
from the parameter like so:
B(A aObject) : object(aObject) { }
This constructor does not call the default constructor, nor does it contain the code contained in the default constructor. Therefore, calling this constructor does not cause output of "hello".
Note that you would still be constructing a new A
(in fact you would be doing so twice, because aObject
is passed by value) but since you did not define the copy-constructor yourself, it wouldn't contain your code that writes a string to std::cout
.
The actual sequence of relevant events that happen here is:
A object;
calls theA::A()
constructor. (The first "hello" is printed from here.)B bObject(object);
will call theB::B(A)
constructor, but because theA
argument is accepted by value,object
is first copied into a new, temporaryA
using the compiler-generatedA::A(const A &)
copy constructor.- The
B::B(A)
constructor is called to createbObject
, passing in the temporaryA
constructed in the last step. - Inside of the
B
constructor, theB::object
object is default-constructed usingA::A()
because it was not in the constructor's initializer list. (The second "hello" is printed from here.) - Finally, the body of the
B::B(A)
constructor is run, which assigns the value of the temporaryA
object (stored inaObject
) to theA
contained inB::object
, which was constructed in the prior step. This assignment is accomplished by using the compiler-generatedA & A::operator=(A const &)
operator.
Why does a move constructor require a default constructor for its members?
Use the constructor's initializer list to initialize the A
member. As written, the move constructor uses, as the compiler says, the default constructor for A
.
B(B&& b) : a(std::move(b.a)) {}
NOT wanting to call the default constructor from child class
The question why the superclass constructor is called, even without explicit super();
call is answered here. One of the constructors of the superclass must always be called. If the superclass has a (possibly implicit) default constructor then the super();
call from the subclass can be omitted, but the constructor is called implicitly. Your Cow
constructor is the same as this one:
public Cow() {
// Calls the `Animal()` superclass constructor
super();
System.out.println("I am a cow");
}
In your specific situation it might make sense to add an additional Animal
constructor which takes the name
and sound
values as parameters and initializes the fields. If you still need a default Animal()
constructor, you can have that delegate to the other constructor:
class Animal {
public String name;
public String sound;
public Animal(String name, String sound) {
// `this.name` refers to the field, `name` refers to the parameter
this.name = name;
this.sound = sound;
}
public Animal() {
// Uses `this(...)` to call the other constructor
this(
"animal",
"an animal makes a sound based on what animal that it is"
);
System.out.println("I am an animal");
}
...
}
Note: If you don't expect these fields to be reassigned, then you should make them final
to protect against bugs and for thread-safety improvements.
Your subclasses can then call the Animal(String, String)
constructor:
public class Cow extends Animal {
public Cow() {
// Calls the `Animal(String, String)` superclass constructor
super("Cow", "Moo");
}
}
This does not declare additional name
and sound
fields because the ones from Animal
are inherited and accessible to Cow
. Your current code for Cow
actually introduces additional fields which hide the ones from Animal
, see this answer.
Related Topics
Compiling a Win32 Gui App (Without a Console) Using Mingw and Eclipse
Where Are Member Functions Stored for an Object
Boost Spirit X3 Cannot Compile Repeat Directive with Variable Factor
Setjmp/Longjmp: Why Is This Throwing a Segfault
How to Find Out If a Tuple Contains a Type
C++ - <Unresolved Overloaded Function Type>
Why Does Reallocating a Vector Copy Instead of Moving the Elements
Is There C/C++ Equivalent of Eval("Function(Arg1, Arg2)")
How to Use a C++ Smart Pointers Together with C's Malloc
How to Declare Variables of Different Types in the Initialization of a for Loop
How to Enable Experimental C++11 Concurrency Features in Mingw
Differencebetween C-Like Casting and Functional Casting
Does C++ Contain the Entire C Language
Familiar Template Syntax for Generic Lambdas