calling constructor of a class member in constructor - c++

Can I call constructor of a member in my Class's constructor?
let say If I have a member bar of class type foo in my class MClass. Can I call constructor of bar in MClass's constructor? If not, then how can I initialize my member bar?
It is a problem of initializing members in composition(aggregation).

Yes, certainly you can! That's what the constructor initializer list is for. This is an essential feature that you require to initialize members that don't have default constructors, as well as constants and references:
class Foo
{
Bar x; // requires Bar::Bar(char) constructor
const int n;
double & q;
public:
Foo(double & a, char b) : x(b), n(42), q(a) { }
// ^^^^^^^^^^^^^^^^^^^
};
You further need the initializer list to specify a non-default constructor for base classes in derived class constructors.

Yes, you can:
#include <iostream>
using std::cout;
using std::endl;
class A{
public:
A(){
cout << "parameterless" << endl;
}
A(const char *str){
cout << "Parameter is " << str <<endl;
}
};
class B{
A _argless;
A _withArg;
public:
// note that you need not call argument-less constructor explicitly.
B(): _withArg("42"){
}
};
int main(){
B b;
return 0;
}
The output is:
parameterless
Parameter is 42
View this on ideone.com

Like this:
class C {
int m;
public:
C(int i):
m(i + 1) {}
};
If your member constructor wants parameters, you can pass them. They can be expressions made from the class constructor parameters and already-initialized types.
Remember: members are initialized in the order they are declared in the class, not the order they appear in the initialization list.

Through initializer list, if base class doesn't have a default constructor.
struct foo{
foo( int num )
{}
};
struct bar : foo {
bar( int x ) : foo(x)
// ^^^^^^ initializer list
{}
};

Yes, you can. This is done in the initialization list of your class. For example:
class MClass
{
foo bar;
public:
MClass(): bar(bar_constructor_arguments) {};
}
This will construct bar with the arguments passed in. Normally, the arguments will be other members of your class or arguments that were passed to your constructor. This syntax is required for any members that do not have no-argument constructors.

Related

Create subclass of class template

The following working code displays the smaller of two given numbers.
#include "stdafx.h"
#include <iostream>
using namespace std;
template <class T>
class Bucky {
public:
Bucky(T a, T b) {
first = a;
second = b;
}
T smaller() {
return (first<second?first:second);
}
private:
T first, second;
};
int main() {
Bucky <int>obj(69, 105);
cout << obj.smaller() << endl;
return 0;
}
I would like to derive from class 'Bucky' and create a subclass having a member function that displays "Hi There!"
Please help.
P.S. Here is my best failed attempt to create my subclass:
template <class T>
class mySubclass : public Bucky<T>
{
public:
mySubclass(T a, T b) { // error C2512: 'Bucky<T>' : no appropriate default constructor available
//first = a;
//second = b;
}
void greet() {
cout << "Hi there!";
}
};
When you construct a derived class, it will also construct its base class. If you don't explicitly specify this, it will attempt to construct the base class using its default constructor (with no arguments). However, your base class doesn't have a default constructor. Instead, you want to delegate to the constructor of Bucky that takes two T arguments:
mySubclass(T a, T b)
: Bucky<T>(a, b) { }
As you can see, this uses a strange syntax beginning with : and leaves the constructor body empty. This syntax is the member initialization list. It says that we're initialising the Bucky<T> base class by passing a and b to its constructor. In fact, you should also use this for your Bucky constructor:
Bucky(T a, T b)
: first(a), second(b) { }
Here we are initialising the first and second members with a and b respectively.
The mySubclass constructor does not explicitly initialize the base class object Bucky. So the compiler will attempt to do so implicitly by calling the default constructor for Bucky. As the error says, Bucky does not have a default constructor. To fix the error, initialize Bucky explicitly in the contructor's member initializer list.
mySubclass(T a, T b)
: Bucky<T>(a, b)
{}
You should also use the member initializer list to initialize Bucky's data members
Bucky(T a, T b)
: first(a)
, second(b)
{}
As the compiler points out, it cannot find an appropriate default constructor for your base class. So, you need to call one explicitely in the member initializer list.
template <class T>
class mySubclass : public Bucky<T>
{
public:
mySubclass(T a, T b) : Bucky<T>(a, b) { }
void greet() {
cout << "Hi there!";
}
};
You can call the base constructor from the derived constructor as such:
mySubClass(T a, T b)
: Bucky(a, b)
{
}
As the error states, by implementing a constructor (one that accepts arguments) you have removed the default constructor. And when you create a constructor for a subclass it must initialize its base class. The way to do this is to call the base constructor in the initializer list, as someone in the comments mentioned.
template <class T>
class a:public Bucky<T> {
public:
a(T r, T l): Bucky<T>(r, l) {}
void Hello(void) { std::cout << "Hello there!" << std::endl; }
};
int main() {
Bucky <int>obj(69, 105);
a<int> obj2(69, 105);
obj2.Hello();
cout << obj.smaller() << endl;
return 0;
}
I think this get's you what you're looking for.

Error : base class constructor must explicitly initialize parent class constructor

I am new to c++. When I try to compile the code below , I get this error
constructor for 'child' must explicitly initialize the
base class 'parent' which does not have a default constructor
child::child(int a) {
here is my class
#include<iostream>
using namespace std;
class Parent
{
public :
int x;
Parent(int a);
int getX();
};
Parent::Parent(int a)
{
x = a;
}
int Parent::getX()
{
return x;
}
class Child : public Parent
{
public:
Child(int a);
};
Child::Child(int a)
{
x = a;
}
int main(int n , char *argv[])
{
}
Why I am getting this error ?
How can I resolve it ?
Thanks in advance
The parent class has an explicit constructor, so compiler will not add an implicit 'empty' constructor to it. Additionally your constructor has a parameter, so compiler can not generate an implicit call to it. That's why you must do it explicitly.
This way:
child::child(int a) : parent(a)
{
}
When you initialize an object of a derived class, the base class part has to be constructed first. If you don't initialize it yourself in the derived class' constructor by calling one of its constructors, the compiler will attempt use the default constructor of the base class. In your case the default constructor is not defined because you already provided a custom constructor.
To solve this you will either have to provide a default constructor for the base class or simply call its constructor in the derived class' constructor's initializer list:
child::child(int a) : parent(a)
{
}
At the risk of repeating the error message you got: a child class constructor must invoke its parent's constructor.
The compiler will add an automatic invocation of the parent's default (argumentless) constructor. If the parent does not have a default constructor, you must explicitly invoke one of the constructors it does have by yourself.
The compiler has to enforce this to ensure that the functionality that the child class has inherited from the parent is set up correctly... for example, initialising any private variables that the child has inherited from the parent, but cannot access directly. Even though your class doesn't have this problem, you must still follow the rules.
Here are some examples of constructors in classes using inheritance:
This is fine, ParentA has a default constructor:
class ParentA
{
};
class ChildA
{
public:
ChildA() {}
};
This is not fine; ParentB has no default constructor, so ChildB1 class must explicitly call one of the constructors itself:
class ParentB
{
int m_a;
public:
ParentB(int a) : m_a(a) {}
};
class ChildB1 : public ParentB
{
float m_b;
public:
// You'll get an error like this here:
// "error: no matching function for call to ‘ParentB::ParentB()’"
ChildB1 (float b) : m_b(b) {}
};
This is fine, we're calling ParentB's constructor explicitly:
class ChildB2 : public ParentB
{
float m_b;
public:
ChildB2(int a, float b) : ParentB(a), m_b(b) {}
};
This is fine, ParentC has a default constructor that will be called automatically:
class ParentC
{
int m_a;
public:
ParentC() : m_a(0) {}
ParentC(int a) : m_a(a) {}
};
class ChildC: public ParentC
{
float m_b;
public:
ChildC(float b) : m_b(b) {}
};
Another example where a MyBook class is being derived from the base class Book. Now a custom constructor with two arguments are supplied for the base class constructor, therefore there is no default constructor for the base class. When inside the main function, a derived class object novel is created, at first the compiler will attempt to invoke the base class constructor which does not exist. So, the base class constructor needs to be explicitly called from the derived class constructor to initialize any private variables that the derived class has inherited from the base class but can not access directly (e.g. title string variable). As user rook mentioned, we need follow these rules. You can get more detailed information from the nice explanation of Initialization Lists by Alex Allain. So, Initialization Lists are must required when there is no defined dafault constructor and also for initializing constant members. He summarises-
Before the body of the constructor is run, all of the constructors for
its parent class and then for its fields are invoked. By default, the
no-argument constructors are invoked. Initialization lists allow you
to choose which constructor is called and what arguments that
constructor receives.
#include <iostream>
#include <cstdio>
using namespace std;
class Book {
private:
string title;
protected:
string author;
public:
Book(string t, string a) {
title = t;
author = a;
};
virtual void display() = 0;
};
class MyBook : public Book {
private:
const string className;
protected:
int price;
public:
// Book(t,a) needs to be called before the {} block to initialize, otherwise error (does not match to Book::Book() default constructor will occur)
MyBook(string t, string a, int p) : Book(t, a), className("MyClass"), price(p){
};
void display() {
cout << "Title: " << getTitle() << endl;
cout << "Author: " << author << endl;
cout << "Price: " << price << endl;
};
};
int main() {
string title, author;
int price;
getline(cin, title);
getline(cin, author);
cin >> price;
MyBook novel(title, author, price);
novel.display();
return 0;
}
Hi Just try add default constructor in your parent class (No argument constructor) then compile it. Hope this might resolve your problem.

C++ , Default constructor

When a constructor in a superclass receives arguments, it is no longer a default constructor, right? For example
class a {
public:
int a;
int b;
a(int c, int d){
cout<<"hello";
};
}
Now when I try to make a subclass, the program causes an error, it says "no default constructor is defined in the super class". How can I solve this problem? I know that if I remove the arguments, everything is going to be fine but I'm told not to do so in my C++ test. Please help me figure it out.
If your base class isn't default-constructible, or if you don't want to use the base class's default constructor, then you simply have to tell the derived class how to construct the base subobject:
struct b : a
{
b(int n) : a(n, 2*n) { }
// ^^^^^^^^^ <-- base class initializer, calls desired constructor
};
You normally deal with this with an initializer list:
#include <iostream>
class a {
public:
a(int c, int d) { std::cout << c << " " << d << "\n"; }
};
class b : public a {
public:
b() : a(1, 2) {}
};
int main() {
b x;
return 0;
}
You have to provide a constructor which takes no argument yourself.
a::a()
{
}
Once you provide any constructor for your class the compiler does not generate the implicit default constructor which takes no arguments. So if your code then needs a no arguments constructor you will have to provide it yourself.

Declaring a member variable that takes a constructor parameter

// In A.h
class A
{
public:
enum eMyEnum{ eOne, eTwo, eThree };
public:
A(eMyEnum e);
}
// In B.h
#include "A.h"
class B
{
B();
private:
A memberA;
}
// In B.cpp
#include "B.h"
B::B(void) : memberA(A::eOne)
{}
The declaration to 'memberA' gives me a compile error using the g++ compiler:
error: 'A::eOne' is not a type
How can I overcome this? Do I simply need to create a default constructor that takes no parameters?
It sounds like you are trying to initialise a member variable. You could do something like:
class B
{
public:
B() : memberA(A::eOne) {} // Initializer list in constructor
private:
A memberA;
};
A constructor expects a eMyEnum. It is not clear why you would want B's constructor to not accept an eMyEnum parameter too. Anyway, assuming that your aim is to pass the argument to A's constructor as A::eOne (as opposed to A::eMyEnum::eOne), you could try the following code, which uses typedef.
#include <iostream>
using namespace std;
class A {
public:
typedef enum { eOne, eTwo, eThree } eMyEnum;
public:
A(eMyEnum e) {
cout << "A ctor" << endl;
}
};
class B {
public:
B() : memberA(A::eOne) {
cout << "B ctor" << endl;
}
private:
A memberA;
};
int main() {
B b;
}
// output
A ctor
B ctor
However, notice that memberA's constructor is always called with the argument as A::eOne. You have not showed how this argument is used in the constructor, but I presume that in your real code it initialises a member of A. If the member must always have the same value, make it const and remove the parameter from the constructor.
class B
{
public:
B(A::eMyEnum someValue = A::eOne) : memberA(someValue) {};
private:
A memberA;
}
eOne is not the type, eMyEnum is the type. What you're essentially saying is that "You must pass the literal 2 into this method" - it doesn't make any sense. If you don't mean to pass an enum into it, you'll have to clarify what you were going for.

When will C++ call the constructor on an object that is a class member?

let's say I have a class
class MyClass {
public:
AnotherClass myObject;
};
My issue is that I want to initialize myObject with arguments to it's constructor, exactly if I were declaring it on the stack during a function
AnotherClass myObject(1, 2, 3);
but I want to do this for the class member in the constructor:
MyClass::MyClass() {
myObject = ...?
...
}
The problem is exactly that. If I declare a class member that has a constructor, will C++ call the default constructor? How can I still declare the variable in the class definition but initialize it in the constructor?
Thanks for any answers!
Use the ctor-initializer. Members are initialized after base classes and before the constructor body runs.
MyClass::MyClass() : myObject(1,2,3) {
...
}
You can use an initializer list.
class MyClass {
public:
MyClass() : myObject(1,2,3){ }
AnotherClass myObject;
};
Google for Constructor initialization lists
http://www.learncpp.com/cpp-tutorial/101-constructor-initialization-lists/
class A
{
public:
A(int);
};
class B
{
public:
B();
private:
A my_a_;
};
// initialize my_a by passing zero to its constructor
B::B() : my_a_(0)
{
}
always use the initializer list:
MyClass::MyClass() :
myObject( 1, 2, 3 )
{
//myObject = don't do this, bad practice!
}
see http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.6
The best method I can think of is to initialize the member in the class ctor, like so:
class MyClass
{
public:
MyClass(int param)
: m_Object(param)
{ };
private:
OtherClass m_Object;
};
You can then explicitly initialize the member with whichever ctor you want (as well as providing multiple ctors with different params for both classes).
Or provide proper constructors:
struct Foo{
Foo(const Bar& b): myBar(b){}
Bar myBar;
}
//...
Foo myFoo1( Bar(1,2,3) );
Foo myFoo2( Bar(3,2,1) );
Or if you don't want to expose bar then you can set parameters, for example
struct Square{
Square(const int height, const int width): myDimension(width,height){}
Dimension myDimension;
}
//...
Square sq(1,2);
Square sq(4,3);