Benefit of Initialization List - Avoiding calls to default constructors - c++

I was reading effective C++ and I couldn't really understand one of the mentioned benefit of initialization list.From what I understand is that initialization lists also help to avoid calling of unnecessary default constructors especially when they are not needed. So in order to test that I created a simple code example as such
class base
{
public:
base()
{
std::cout << "Default Constructor called \n";
}
base (int i)
{
std::cout << "Int constructor called \n";
}
};
class der : public base
{
private:
base b;
public:
der(int i):b(i)
{
std::cout << "Derived constructor called \n";
}
};
void main()
{
der d(12);
}
No where I assumed that only the int constructor will be called instead both the constructors of the base class are called. Could anyone please clarify this concept.

The problem is that you actually have 2 instances of base, one as a member and one as a base. Either change into der(int i):base(i),b(i) or remove the member.

Keep in mind that you are adding a member of type base to the der class, which also needs to be constructed. That member is being initialized with the constructor that doesn't take arguments. What you probably meant was:
class base
{
private:
int num;
public:
base()
{
std::cout << "Default Constructor called \n";
}
base (int i) : num(i)
{
std::cout << "Int constructor called \n";
}
};
class der : public base
{
private:
//base b;
public:
der(int i):base(i)
{
std::cout << "Derived constructor called \n";
}
};
void main()
{
der d(12);
}

der has two base instances, as explained by Ylisar. As base has default constructor, it will be implicitly called in der constructor.
Also C++ only supports below two forms of main function, there is no void main() in C++
§3.6.1 Main function
An implementation shall not predefine the main function. This function
shall not be overloaded. It shall have a return type of type int, but
otherwise its type is implementation-defined. All implementations
shall allow both of the following definitions of main:
int main() { /* ... */ }
and
int main(int argc, char* argv[]) { /* ... */ }

In your der,There are two base class, one is for inheriting, another one is b(the member of der).

Related

use protected ctor from virtual base class in derived class

I have an abstract pseudo base class for some audio formats with 2 ctors - one works for the derived class but the other one gives me an error which i can´t solve.
It says that i can´t access the protected member declared in MP3, but why can it reach one ctor but not the other?
class Audioformat
{
protected:
string song="";
Audioformat(string s) :song(s) {};//This ctor gives me the error
Audioformat() { song = "unknown";}
public:
virtual void play()=0;
virtual void info() = 0;
virtual ~Audioformat() = 0 {};
};
class MP3 : public Audioformat
{
public:
using Audioformat::Audioformat;
void play() { cout << "pseudo-play" << endl; }
void info() { cout << song << endl; }
~MP3() { cout << "MP3" << endl; delete this; }
};
Here´s my main :
int main()
{
MP3 song1{};//WORKS
MP3 song2{ "random trash song" };//ERROR MP3::MP3(std::string) is inaccessible
play(song1);
info(song1);
getchar();
return 0;
}
Two reasons:
Using declarations alone do not suppresses the implicit declaration of a special class member. In this case the default c'tor ([namespace.udecl]/4):
the using-declaration does not by itself suppress the implicit
declaration of the derived class member
So a public default c'tor for MP3 is synthesized by the compiler, and invoked in your example.
The c'tors introduced by a using declaration basically have the same accessibility they had in the base class ([namespace.udecl]/19):
A using-declarator that names a constructor
does not create a synonym; instead, the additional constructors are
accessible if they would be accessible when used to construct an
object of the corresponding base class, and the accessibility of the
using-declaration is ignored.
So the c'tor taking a string is not accessible in main since it's protected in MP3 as well.
If you want to have a public c'tor in MP3 that accepts a std::string you have to define it in full, and forward to the base class c'tor explicitly:
public:
MP3(std::string s) : Audioformat(s) {}

Virtual functions default parameters

Could anybody explain where c++ compilers keep default values for parameters for virtual functions? I know it is a bad idea to change these parameters in child classes but why?
Thanks.
It's a bad idea because they aren't kept anywhere.
The default values that are used will be those defined in the static (compile-time) type. So if you were to change the default parameters in an override, but you called the function through a base class pointer or reference, the default values in the base would be used.
#include <iostream>
struct Base
{
virtual ~Base(){ }
virtual void foo(int a=0) { std::cout << "base: " << a << std::endl; }
};
struct Derived : public Base
{
virtual ~Derived() { }
virtual void foo(int a=1) { std::cout << "derived: " << a << std::endl; }
};
int main()
{
Base* derived = new Derived();
derived->foo(); // prints "derived: 0"
delete derived;
}
Giving virtual functions default argument initializers tends to defeat polymorphism and introduce unnecessary complexity into a class hierarchy.
consider the following non compliant code
class Thing {
public:
virtual ~Thing();
virtual void doItNTimes( int numTimes = 10 );
virtual void doItThisHigh( double howHigh = 1.0 );
// ...
};
class MyThing : public Thing {
public:
void doItNTimes( int numTimes );
void doItThisHigh( double howHigh = 2.2 );
// ...
};
A default initializer is not part of the type of a function signature and does not participate in overriding or hiding. Therefore both of the base class virtual functions shown in this Non-Compliant Code Example are overridden in the derived class. However, the differences in the status of default argument initializers in the base class and derived class interfaces causes differences in behavior depending on which interface is used to access an object.
MyThing *mt = new MyThing;
Thing *t = mt;
t->doItNTimes(); // default of 10
mt->doItNTimes(); // compile time error!
t->doItThisHigh(); // default of 1.0!
mt->doItThisHigh(); // default of 2.2
In this piece of code, the intention of the designer of the MyThing class is not clear. Presumably, it is important that the default value to doItThisHigh for an object of type MyThing be 2.2. However, it is not clear whether that value should also be used by default when a MyThing is manipulated through its Thing interface.
For more details Please refer the below link https://www.securecoding.cert.org/confluence/display/cplusplus/OOP04-CPP.+Prefer+not+to+give+virtual+functions+default+argument+initializers

Is this correct: virtual method of Derived called before constructing Base object?

I know that within constructor of Base class - when calling virtual method - the Base method is called, not derived - see Calling virtual functions inside constructors.
My question is related to this topic. I've just wondered what happens if I call virtual method in Derived class constructor - but before constructing Base part. I mean calling virtual method to evaluate Base class constructor argument, See code:
class Base {
public:
Base(const char* name) : name(name) {
cout << "Base():" << name << endl;
}
virtual const char* getName() {
cout << "Base::getName()" << endl;
return "Base";
}
protected:
const char* name;
};
class Derived : public Base {
public:
Derived() : Base(getName()) {
cout << "Derived():" << name << endl;
}
virtual const char* getName() {
cout << "Derived::getName()" << endl;
return "Derived";
}
};
int main() {
Derived d;
}
Compiler g++ (4.3.x-4.5x versions) output is:
Derived::getName()
Base():Derived
Derived():Derived
However I'd expect:
Base::getName()
Base():Base
Derived():Base
This does not look wrong - but consider this example, which produces segmentation fault:
class Derived : public Base {
public:
Derived() : Base(getName()), name(new string("Derived")) {
cout << "Derived():" << Base::name << endl;
}
virtual const char* getName() {
cout << "Derived::getName()" << endl;
return name->c_str();
}
private:
string* name;
};
Please answer: Is this correct g++ behavior? What C++ standard says about that? Maybe it is undefined behavior?
[UPDATE1]
I take into consideration Robert and Oli answers - and I changed my first example. Then it getName() is called "virtual" - and it produces Segmentation Fault. Please answer my question to this part too.
const char* virtualGetName(Base* basePtr)
{
return basePtr->getName();
}
class Derived : public Base {
public:
Derived() : Base(virtualGetName(this)) {
cout << "Derived():" << Base::name << endl;
}
virtual const char* getName() {
cout << "Derived::getName()" << endl;
return "Derived";
}
};
All of your examples exhibit undefined behavior. The C++ language standard states (C++11 §12.6.2/13):
Member functions (including virtual member functions) can be called for an object under construction. Similarly, an object under construction can be the operand of the typeid operator or of a dynamic_cast.
However, if these operations are performed in a ctor-initializer (or in a function called directly or indirectly from a ctor-initializer) before all the mem-initializers for base classes have completed, the result of the operation is undefined.
You are calling the member function getName() from the initialization list (the ctor-initializer) of the Derived class constructor. This member function call must take place before the initializer for Base completes (the mem-initializer for Base) because it is an argument to the initializer itself.
Therefore, the behavior is undefined.
As a rule, Never Call Virtual Functions during Construction or Destruction.
I've just wondered what happens if I call virtual method in Derived class constructor - but before constructing Base part.
It might look like you're doing this, but you're not.
In your first example, Derived::getName() does not depend on this, so the method call works. In your second example, Derived::getName() does depend on this. Since this->name is not yet set, it points to an undefined location and gives you a segfault.
this->name is not yet set, because the first thing the Derived constructor does is call the Base constructor. If you specify the parameters to pass to the Base constructor, it processes them first. Then it instantiates the member variables of the class by calling their constructors. The initializer list can be used to pass parameters to those constructors, but it cannot change the order in which they get called. This step is where name gets initialized. Finally, the body of the Derived constructor is executed.

Didn't understand the following comment (in bold) on Bruce Eckel's "Thinking in C++" on its page 624 Vol. 1

#include <fstream>
using namespace std;
ofstream out("order.out");
#define CLASS(ID) class ID { \
public: \
ID(int) { out << #ID " constructor\n"; } \
~ID() { out << #ID " destructor\n"; } \
};
CLASS(Base1);
CLASS(Member1);
CLASS(Member2);
CLASS(Member3);
CLASS(Member4);
class Derived1 : public Base1 {
Member1 m1;
Member2 m2;
public:
Derived1(int) : m2(1), m1(2), Base1(3) {
out << "Derived1 constructor\n";
}
~Derived1() {
out << "Derived1 destructor\n";
}
};
class Derived2 : public Derived1 {
Member3 m3;
Member4 m4;
public:
Derived2() : m3(1), Derived1(2), m4(3) {
out << "Derived2 constructor\n";
}
~Derived2() {
out << "Derived2 destructor\n";
}
};
int main() {
Derived2 d2;
}
"Note that the
constructors are not default constructors; they each have an int
argument. The argument itself has no identifier; its only reason for
existence is to force you to explicitly call the constructors in the
initializer list"
As the classes have a user-defined constructor and that user-defined
constructor is not the default constructor, there is no default
constructor available in those classes.
This makes it necessary to explicitly mention one of the available
constructors in the member initializer list of a derived class.
class Derived : public Base {
Derived() {} // fails to compile, no constructor Base::Base() available
Derived() : Base(3) {} // works
};
So much for what the code does and how it achieves it. I have no idea
why you should ever need something like that, but you never know.
What it means that the argument has no identifier - no name - and thus it is not used anywhere in the constructor.
But, when you make an object that belongs to the derived class, it's constructor calls the constructor of the parent class. Also, when you have an object member, you have to initialize it in your constructor.
If the parent class had a default (no-arguments) constructor, you would not have to call it at all - it would have been done automatically. Also, if you do not initialize the object member, it will be done automatically via the default constructor.
Since none of your classes actually have a default constructor, you have to explicitly call the parent class constructor, and also initialize members via their only existing constructor with one argument.
Using the unnamed argument in all the classes does just that - forces you to explicitly call their constructors, instead of just relying on the default constructor being called.
Providing a constructor that takes an argument prevents the compiler from synthesising a default constructor. This forces the user of the ID class to provide an int, which is discarded, when creating an instance of this class. I can see no practical application of this approach.
To simplify this demonstration code:
#include <iostream>
struct ID
{
ID(int)
{
std::cout << "ID constructor" << std::endl;
}
};
int main()
{
ID this_will_compile(0);
ID this_will_not_compile;
}
While the first creation of an instance of ID will succeed, the second attempt will fail. You compiler will tell you something like:
error: no matching function for call to ‘ID::ID()’
The same is true for deriving from such a class:
This will work...
struct DerivedWorking: public ID
{
DerivedWorking()
:ID(0)
{
}
};
Whereas this will not, because it doesn't provide an int to ID's constructor...
struct DerivedBroken: public ID
{
DerivedBroken()
{
}
};

Override or remove an inherited constructor

Here is some C++ code:
#include <iostream>
using namespace std;
class m
{
public:
m() { cout << "mother" << endl; }
};
class n : m
{
public:
n() { cout << "daughter" << endl; }
};
int main()
{
m M;
n N;
}
Here is the output:
mother
mother
daughter
My problem is that I don't want the m's constructor to be called when I create N. What should I do ?
AFAIK, you cannot remove inherited constructor.
The problem in your example comes from incorrect class design.
Constructor is normally used for allocating class resources, setting default values, and so on.
It is not exactly suitable to be used for outputting something.
You should put
n() { cout << "daughter" << endl; }
Into virtual function.
In general - if you have a need to remove inherited constructor, then you probably need to rethink/redesign your class hierarchy.
class m
{
public:
m(bool init = true) { if (init) cout << "mother" << endl; }
};
class n : m
{
public:
n() : m(false) { cout << "daughter" << endl; }
};
or if you don't want it to be public
class m
{
protected:
m(bool init) { if(init) Init(); }
Init() { cout << "mother" << endl; }
public:
m() { Init(); }
};
class n : m
{
public:
n() : m(false) { cout << "daughter" << endl; }
};
Two solutions:
Don't derive n from m. Check that you really have interface reuse (that you rely on a polymorphic interface) instead of implementation reuse. In the latter case, prefer making an m* a member of n and then only create the m object when needed. This would be my preferred solution.
You probably don't want ms contructor to be called because it does something which you don't want. Move that code which you don't want to execute out of ms constructor into a dedicated init() function or the like, and then call it as needed. I don't recommend this because you end up with a stateful interface.
Constructors are never inherited. What happens is that C++ generates a default nullary constructor that initializes the base classes and members of class type. The base classes are always initialized and there is no way to prevent this, so if you don't want the base class constructors to be called, don't inherit from the base class.
Object of any class contains in it sub-objects of all its superclasses. And all of them must be constructed before construction of main object. Part of this construction is calling one of base class constructors and it cannot be omitted. You can only choose constructor to be called.