probably it's super easy, but can someone tell me how I can call the superclass' constructor with arguments calculated in the subclass' constructor? something like this:
class A{
A(int i, int j);
};
class B : A{
B(int i);
};
B::B(int i){
int complex_calculation_a= i*5;
int complex_calculation_b= i+complex_calculation_a;
A(complex_calculation_a, complex_calculation_b);
}
//edit: i edited the example so that the superclass takes two arguments which have a relation to each other
If you cannot express your calculation in a single-line expression, add a static function, and call it in the way you normally call the constructor of the superclass:
class B : A{
public:
B(int i) : A(calc(i)) {};
private:
static int calc(int i) {
int res = 1;
while (i) {
res *= i--;
}
return res;
}
};
EDIT Multiple-argument case:
class B : A{
public:
B(int i) : A(calc_a(i), calc_b(i)) {};
private:
static int calc_a(int i) {
int res = 1;
while (i) {
res *= i--;
}
return res;
}
static int calc_b(int i) {
int complex_a = calc_a(i);
return complex_a+10;
}
};
B::B(int i)
: A(i * 5)
{}
With C++11, a more complex way is
B::B(int i)
: A(([](int x) { return 5 * x; })(i))
{}
For complex cases, a protected init function is more readable.
Only like this:
class A{
A(int i);
};
class B : A{
B(int i);
};
B::B(int i) : A(i*5) {
}
The call to the parent's constructor can only come in the initialization list. Which means, that whatever you're calculating must be known before B is fully constructed (i.e.: you can't call a B member function, unless its static, but only to rely on the parameters passed to B)
struct A
{
A(int);
};
struct B : public A
{
B()
: A(5) // "initialisation list"
{}
};
You have to do this inside the list, but you can use a function.
Edit: If you use a function, you probably want to make it a private static member of B.
class A
{
public:
A(int i){}
};
class B : public A
{
public:
B(int i):A(i*5){}
};
Related
I'm new to inheritance in C++ and decided to try some experiments to learn about this subject.
The code below shows the hierarchy of classes I'm creating:
classes.h
class base
{
protected:
int _a;
int _b;
int _c;;
base(int b, int c);
};
class sub_one : public virtual base
{
public:
sub_one(int a, int b) : base(a, b)
{
// do some other things here
}
// other members
};
class sub_two : public virtual base
{
protected:
int _d;
public:
sub_two(int a, int b, int c = 0) : base(a, b)
{
// do something
}
// other members
};
class sub_three : public sub_one, public sub_two
{
private:
bool flag;
public:
sub_three(int a, int b, int c = 0) : base(a, b)
{
// do something
}
};
classes.c
base::base(int a, int b)
{
// ...
}
The compiler shows me the messages:
no matching function for call to sub_one::sub_one()
no matching function for call to sub_one::sub_one()
no matching function for call to sub_two::sub_two()
no matching function for call to sub_two::sub_two()
I just can't find out what is wrong.
sub_three(int a, int b, int c = 0) : base(a, b)
{
// do something
}
is equivalent to:
sub_three(int a, int b, int c = 0) : base(a, b), sub_one(), sub_two()
{
// do something
}
Since there are no such constructors in sub_one and sub_two, the compiler reports the errors. You can add default constructors to sub_one and sub_two to remove the errors.
sub_three constructor initializes base, and call the default constructor of sub_one and sub_two which doesn't exist, you may need
class sub_three : public sub_one, public sub_two
{
private:
bool flag;
public:
sub_three(int a, int b, int c = 0)
: base(a, b), sub_one(a,b), sub_two(a,b,c), flag(false)
{
// do something
}
};
Let's say I have two classes, A and B:
class B;
class A
{
private:
int an_int;
B *something_else;
public:
A(int n) : an_int(n), something_else(nullptr) {}
};
class B
{
private:
int an_int;
A *something_else;
public:
B(int n) : an_int(n), something_else(nullptr) {}
};
How can I make it so that I don't have to prototype B in order to have a pointer to a B object in class A?
This solution is most probably what is intended in an exercise about inheritance where you can't use a forward declaration.
Instead of the forward declaration
class B;
you can define an interface like
struct I_whoop
{
virtual void whoop_whoop() = 0;
};
then let class B implement that interface, and just use a pointer to the interface.
Actually You can not if using concrete class.
But You can achieve your goal by using template parameters. Making class B a template parameter of template class A.
How can I make it so that I don't have to prototype B in order to have a pointer to a B object in class A?
Like this:
class A
{
private:
int an_int;
class B *something_else;
public:
A(int n) : an_int(n), something_else(nullptr) {}
};
class B
{
private:
int an_int;
class A *something_else;
public:
B(int n) : an_int(n), something_else(nullptr) {}
};
In C and C++ it has never been necessary for a type T to be
forward declared before the declaration of objects of type T *
(or const variants), because the declaration of a T * per se requires
the compiler only to know the size of a T *, not the size or definition
of a T, and the size of a T * is the same, regardless of T.
Here is a more fleshed-out illustration:
class A
{
private:
int an_int;
class B *something_else;
public:
A(int n, class B * pb = nullptr) : an_int(n), something_else(pb) {}
int get_int() const {
return an_int;
}
void set_B(class B * pb) {
something_else = pb;
}
class B * get_B() const {
return something_else;
}
};
class B
{
private:
int an_int;
class A *something_else;
public:
B(int n, class A * pa = nullptr) : an_int(n), something_else(pa) {}
int get_int() const {
return an_int;
}
void set_A(class A * pa) {
something_else = pa;
}
class A * get_A() const {
return something_else;
}
};
#include <iostream>
int main()
{
A a(1);
B b(2);
a.set_B(&b);
b.set_A(&a);
std::cout << a.get_B()->get_int() << std::endl;
std::cout << b.get_A()->get_int() << std::endl;
return 0;
}
Output:
2
1
(gcc 4.9.2/clang 3.5.2 -std=c++11 -Wall -pedantic)
I have a class A and class B, B here is a subclass of A:
class A {
public:
A(int a) : obj(a) {}
void init() {
if(magic_str == "hello") {
// do init c
c = 7;
}
}
private:
int obj;
int c;
protected:
string magic_str;
};
class B : public A {
public:
B(int a, double _b) : A(a), b(_b){}
void set_magic_str() {
magic_str = "hello";
}
private:
double b;
};
Above, the init function in A must be constructed in A, but must be called after magic_str is initialized. magic_str must be initialized in class B because there are some user-define logic.
How can I force B to invoke init in A?
To sum up, I want to split constructor code in A into two piece, and between these two piece, some user-defined behavior must be initialized in his subclass B.
One way would be to pass the magic string as an constructor to As constructor and call init in the constructor.
class A {
public:
A(int a, string m) : obj(a), magic_str(m)
{
init();
}
void init() {
if(magic_str == "hello") {
// do init c
c = 7;
}
}
private:
int obj;
int c;
protected:
string magic_str;
};
class B : public A {
public:
B(int a, double _b) : A(a,get_magic_str()), b(_b){}
static string get_magic_str() {
return "hello";
}
private:
double b;
};
Another way would be to use the builder pattern and let it handle the complex way you want your object to be created:
class A {
public:
A(int a) : obj(a) {}
void init() {
if(magic_str == "hello") {
// do init c
c = 7;
}
}
private:
int obj;
int c;
protected:
string magic_str;
};
class B : public A {
public:
static B create (int a, double _b) // <-- only allow instances to be created via this function
{
B b = B(a, _b);
b.init();
return b;
}
void set_magic_str() {
magic_str = "hello";
}
private:
B(int a, double _b) : A(a), b(_b){} //maybe protected
double b;
};
As init is a non-private member function of A, B being derived form A, can call init.
Call it after magic_string is set eg. the constructor.
A::init();
Otherwise,change A's constructor , and use this in B.
A(int a, string s)
B(int a, double _b): A (a, magic_str)...
I would change the logic to something like:
class A {
public:
A(int a) : obj(a), c(0) {}
protected:
void set_magic_str(const std::string& s) {
magic_str = s;
if (magic_str == "hello") {
// do init c
c = 7;
}
}
private:
int obj;
int c;
std::string magic_str;
};
class B : public A {
public:
B(int a, double _b) : A(a), b(_b){}
void set_magic_str() {
A::set_magic_str("hello");
}
private:
double b;
};
I want to write a function that works for any derived classes in a certain hierarchy, without modifying the abstract class input parameter:
class A {
public:
A(int val): m_i(val) { }
virtual void add(int i) = 0;
int m_i;
};
class B: public A {
public:
B(int val): A(val) { }
B(): A(0) { }
virtual void add(int i) { m_i += i; }
};
class C: public A {
public:
C(int val): A(val) { }
C(): A(0) { }
virtual void add(int i) { m_i += i*2; }
};
int f(const A& base_class)
{
// how to create a concrete copy of class base_class?
base_class.add(5);
}
Here f() should work for both B and C, but I can't create a copy of the concrete class because I don't know the actual type, unless I use dynamic_cast.
Is there another approach to solve this problem or should just use dynamic_cast?
The typical approach commonly known as the virtual constructor idiom is to define another virtual method for cloning the concrete class, make it virtual in the abstract base, and call it as needed to produce instances of the desired class without knowing its type:
class A {
public:
A(int val): m_i(val) { }
virtual void add(int i) = 0;
virtual A* clone() const = 0; // Override in derived classes to return new B/C
int m_i;
};
It is not clear from your question why you even need to make a copy.
However, if you do, you could have a clone() method:
class A {
public:
virtual A* clone() const = 0;
};
class B: public A {
public:
virtual B* clone() const { return new(*this); }
};
class C: public A {
public:
virtual C* clone() const { return new(*this); }
};
The problem is that you are passing const A& but add is not a const method if you take away the const modifier then this works:
int f(A& base_class)
{
// how to create a concrete copy of class base_class?
base_class.add(5);
///Need a return here
}
I am using gcc and the error that really tells you what is going is this:
error: no matching function for call to 'A::add(int&) const'
base_class.add(a); ^^^^^
no known conversion for implicit 'this' parameter from 'const A*' to 'A*'
^^^^^^^^
Based on your response the other option is make m_i mutable and make the member methods const like so:
class A {
public:
A(int val): m_i(val) { }
virtual void add(int i) const = 0;
protected:
mutable int m_i;
};
class B: public A {
public:
B(int val): A(val) { }
B(): A(0) { }
virtual void add(int i) const { m_i += i; }
};
class C: public A {
public:
C(int val): A(val) { }
C(): A(0) { }
virtual void add(int i) const { m_i += i*2; }
};
int f(const A& base_class)
{
base_class.add(5) ;
//Need a return here
}
This simple example demonstrates the C++ syntax for calling base class constructors - as far as I understand it as a C++ learner:
class BaseClass {
protected:
int i;
public:
BaseClass(int x) {
i = x;
}
};
class DerivedClass: public BaseClass {
int j;
public:
DerivedClass(int x, int y): BaseClass(y) {
j = x;
}
Here, the base class constructor can take named arguments to the derived class constructor as input.
Now, what if I want to call BaseClass() constructor with an input value that is not a direct input to DerivedClass()? Basically, I'd like to do some multiline work with x and y within DerivedClass(), then pass a calculated value to BaseClass(). Can this be done with constructors? Should this be done with some kind of initializer method instead?
You can do that, yes:
class BaseClass
{
public:
BaseClass(int x) : i(x) {}
private:
int i;
};
class DerivedClass: public BaseClass
{
public:
DerivedClass(int x, int y):
BaseClass(compute(x, y)), // Neither i or j are initialized here yet
j(x)
{}
private:
static int compute(int a, int b) { return a + b; } // Or whatever
int j;
};
Note that you can even make compute() a non-static method but be aware that DerivedClass or BaseClass members won't be initialized at the time of the call. So you won't be able to rely on their values.
If you're using C++11 or newer you can also use lambda expressions:
class BaseClass
{
public:
BaseClass(int x) : i(x) {}
private:
int i;
};
class DerivedClass: public BaseClass
{
public:
DerivedClass(int x, int y): BaseClass(
[=]()->int
{
int sum = 0;
for(int i = 0; i < x; ++i)
{
sum += y + i * x;
}
return sum;
}()), j(x)
{}
private:
int j;
};
Then you can do this:
DerivedClass(int x, int y): BaseClass(compute(x,y)), j(y) {
//j = x; //use member-initialization-list ---> ^^^^
}
int compute(int x, int y)
{
//your code
}