Create subclass of class template - c++

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.

Related

Manually calling constructor of base class outside initialization list

I have a Derived class whose constructor has to populate the fields of a struct that is passed as an argument to the constructor of the Base class. I want to be able to name the fields of the struct that I am populating, to keep my code future-proof (i.e.: resistant to addition and/or reordering of the members of MyStruct).
Note that struct MyStruct has default values, so it cannot be initialised with named fields directly in the initialization list (e.g.: Base({.a = a, .b = b}) does not work). Also, in my case, Base's copy constructor is deleted. Also, I am using C++ 11.
The solution I came up with uses the placement new operator to manually call the constructor of the Base class on the memory pointed to by this. To achieve this I also had to add a protected default constructor to my Base class. Are there any possible downsides to this approach and/or could anyone suggest a better method?
#include <iostream>
struct MyStruct
{
int a = 0;
int b = 1;
};
class Base
{
public:
Base(MyStruct str){
std::cout << "a: " << str.a << ", b: " << str.b << "\n";
}
Base(Base&&) = delete; // no copy constructor
protected:
Base(){ // dummy, does exactly nothing.
// it only exists to be called by
// the derived class's constructor
}
private:
int amember;
};
class Derived : public Base
{
public:
Derived(int a, int b)
{
MyStruct str;
str.a = a;
str.b = b;
new (this) Base(str);
}
private:
int anothermember;
};
int main()
{
MyStruct str;
str.a = 10;
str.b = 20;
Base b(str);
Derived d(10, 20);
return 0;
}
edit: added mention that Base cannot be copied, made explicit that Base::Base() does exactly nothing.
Use a helper function instead like
class Derived : public Base
{
public:
Derived(int a, int b) : Base(make_mystruct(a, b)), anothermember(some_value) {}
private:
int anothermember;
static MyStruct make_mystruct(int a, int b) { return MyStruct(a, b); }
};
I would just like to add that this could be a good opportunity to use IILE, Immediately Invoked Lambda Expression, if you for whatever reason don't want a named helper function:
class Derived : public Base
{
public:
Derived(int a, int b) : Base{[](){
MyStruct str;
str.a = a;
str.b = b;
return str; }()}
{}
};
The benefit is that you will not need to construct the class and it's members only once, since you do everything in the initialization list. If you in the future add non-trivial members to Base, you will be will not have to pay for double initialization.

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.

calling constructor of a class member in constructor

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.

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.