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
}
Related
I've currently got code below in which i am trying to initialize the data members x, y and z to 0 when an object of type Solid is being instantiated. The lines 25, 26 and 27 contain errors, how would I rewrite these lines to access the x and y members and set them to 0?
edit 1: I've written out my code below.
edit 2: To clear things up, the only lines of code that can be altered are the lines that contain errors. The derived class should be rewritten to access the private data members.
class Shape
{
private:
int x, y;
protected:
string _type;
public:
Shape() { x = y = 0; }
Shape(int a, int b) { x = a; y = b; }
string type() { return _type; }
void stype(string val) { _type + val; }
int getx() { return x; }
int gety() { return y; }
};
class Solid : public Shape
{
int z;
public:
Solid() { x = y = z = 0; } // errors
Solid(int a, int b, int c) { x = a; y = b; z = c; } //
int Volume() { return x * y * z; } //
};
int main()
{
Solid ob1;
return 0;
}
You can't access private members of a base class, and the point of this exercise is that you don't need to - not that you should come up with a way of doing it.
Your default constructor should only set its own member - Shapes default constructor takes care of its own members:
Solid() { z = 0; }
or (the preferred method, which actually is initialisation and not an assignment)
Solid() :z(0) {}
The other constructor should initialise the base, and then z:
Solid(int a, int b, int c) : Shape(a,b), z(c){}
and Volume should use the provided accessors:
int Volume() { return getx() * gety() * z; }
Inherited class can not access to parent's private attributes. It can access his protected attributes, so you can move your variables to protected. Another option is to use setter function (like getX) and use them.
edit: change only for the relevant errors lines:
Solid():Shape(0,0) { this->z = 0; }
Solid(int a, int b, int c):Shape(a,b) { this->z = c; }
int Volume() { return this->getx() * this->get.y * this->z; }
when you create Solid object, you can also call for the c'tor of Shape with the values you want. That is the right way to initialize values of x, y when creating new inherited objects. For the third line calculation you should use getx() and gety() functions.
As said before, the key is to understand that x and y are not directly accessible for Solid object
You can't, directly, inherit the private members of the parent class. You could use its constructor in your derived class(child class) constructor though-its cool, but I don't use that way. Some information about the access specifiers(the type of inheritance you declare):
Public: Your derived class inherits the protected members of your parent class as protected and the public as public.
Protected: Your derived class inherits the protected members of your parent class as protected and the public as protected.
Private: Your derived class inherits the protected members of your parent class as private and the public as private.
Notice again that the private members of your parent class are not inherited. This should do the trick:
Change:
private:
int x, y;
Into:
protected:
int x, y;
Using the parent class constructor should look like:
class Solid : public Shape
{
private://doesn't matter, just for the aesthetics
int x;
int y;
int z;
public:
Solid() {
Shape();
z = 0; } // errors
And the direct way is(your code with added x,y as properties of the class):
class Solid : public Shape
{
private://doesn't matter, just for the aesthetics
int x;
int y;
int z;
public:
Solid() {x=y=z = 0; } // errors
Private data members are never inherited in any type of inheritance. Hence the name private, but interestingly you can use friend class concept here and even private data members are inherited now,
please try to run the following code:
#include <bits/stdc++.h>
using namespace std;
class Shape
{
private:
int x, y;
protected:
string _type;
public:
Shape() { x = y = 0; }
Shape(int a, int b) { x = a; y = b; }
string type() { return _type; }
void stype(string val) { _type + val; }
int getx() { return x; }
int gety() { return y; }
friend class Solid;
};
class Solid : public Shape
{
int z;
public:
Solid() { x = y = z = 0; } // errors
Solid(int a, int b, int c) { x = a; y = b; z = c; } //
int Volume() { return x * y * z; } //
};
int main()
{
Solid ob1;
return 0;
}
Now you can access x, y in inherited class also, since you declared class solid as friend of shape class.
Hope this answers your question.
I am doing C++ from 2 years or so , I say why we need constructors in class and not in structures , and why we cant do constructor overloading in structure...
why we need constructors in class
We don't.
// Perfectly valid
class Foo
{
public:
int x
};
why we cant do constructor overloading in structure...
We can.
// Look, ma!
struct Bar
{
Bar operator+(const Bar& other);
};
I don't know where you heard these claims but it certainly wasn't from trying it out.
A user-defined type declared with the keyword struct is a class.
The only difference between struct and class in C++ is visibility; a struct defaults to public while a class defaults to private.
Once you get past that initial visibility, however, they are indistinguishable. A struct is a class with default public visibility.
These two pieces of code have exactly the same effect.
struct MyClass {
MyClass(int i) : m_i(i) {}
int getI() const { return m_i; }
void setI(int i) { m_i = i; }
private:
int m_i;
};
// is exactly the same as
class MyClass {
public:
MyClass(int i) : m_i(i) {}
int getI() const { return m_i; }
void setI(int i) { m_i = i; }
private:
int m_i;
};
or put another way
class MyClass {
int m_i;
public:
MyClass(int i) : m_i(i) {}
int getI() const { return m_i; }
};
struct MyClass {
private:
int m_i;
public:
MyClass(int i) : m_i(i) {}
int getI() const { return m_i; }
};
I want to create 2 kind of classes.
the classes will have similar function "set", but the set funct will get "int" in class B and double in class C. (A is abstract calss but it does not require).
What do I need to do?
class A{
int x;
public:
A (int t=1): x(t){}
virtual void set ()=0;
}
class B: public A{
int y;
public:
virtual void set (int y);
};
class C: public A{
double y;
public:
virtual void set (double y);
};
void main ()
{
B b; //error
C c; //error
}
Create a single template class and instantiate which ever you need at the time, or typedef B and C from the template class:
template< typename T > class A
{
public: A() : mValue() {}
void Set( T value ) { mValue = value; }
private: T mValue;
};
typedef A< int > B;
typedef A< double > C;
There are pretty many variants to solve this, but first of all, virtual function has to have the same signature (there could be an exception, but that's irrelevant for your case). So solution is to have and argument(s) that will solve all cases. There are variants:
Pass all variants to the function, and use only particular one:
class A {
public:
virtual void set( int, double ) = 0;
};
class B {
int y;
public:
virtual void set( int val, double ) { y = val; }
};
class C {
double y;
public:
virtual void set( int , double val ) { y = val; }
};
This is not very good solution and does not scale well, so we can use union:
Union Arg {
int i;
double d;
};
class A {
public:
virtual void set( Arg a ) = 0;
};
// derived classes are trivial, so omitted
Union is not type safe, so we can use boost::variant instead
Another solution to have another hierarchy for parameter:
struct Arg {
virtual ~Arg();
};
struct IntArg : Arg {
int m_value;
};
struct DoubleArg : Arg {
double m_value;
};
class A {
virtual void set( const Arg &a ) = 0;
};
class B {
int y;
public:
virtual void set( const Arg &a ) { y = dynamic_cast<const IntArg &>( a ).m_value; }
};
class C {
double y;
public:
virtual void set( const Arg &a ) { y = dynamic_cast<const DoubleArg &>( a ).m_value; }
};
You can use static_cast and then you will not need virtual destructor in Arg, but that is less safe.
These are only some variants, there could be much more, which one suits you best you can only decide based on your program requirements.
Ditch the inheritance and virtual thing. You can't easily access a statically unknown type result via a virtual function. So:
class A
{
private:
int x_;
public:
A( int const t = 1 ): x_( t ) {}
};
class B
: public A
{
private:
int y_;
public:
void set( int const y );
};
class C
: public A
{
private:
double y_;
public:
void set( double const y );
};
int main ()
{
B b; // OK
C c; // OK
}
Note the semicolon at the end of class A and the int main instead of void main.
Such details matter.
Otherwise you can send people who want to help you, on long wild goose chases. And you don't want that, do you? So, make sure the code you post has been accepted by a compiler, except possibly for the troublesome parts that you want to show do not compile.
The trick is to find common parts of B and C, and put them to base class. The stuff that is different should go to constructor parameter of the derived class:
class A {
virtual std::string get() const=0;
virtual void set(std::string s)=0;
};
class B : public A { B(int a) : a(a) { } int a; };
class C : public A { C(float b) : b(b) { } float b; }
To implement the functions, you'll need the following:
void B::set(std::string s) {
stringstream ss(s);
ss >> a;
}
void C::set(std::string s) {
stringstream ss(s);
ss >> b;
}
The functions look the same, but are actually calling different operator>>.
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){}
};
For the below code snippet, how do I initialize instances of class Enemy with variables (such as x, y, type)? I have it working correctly, it triggers the instances no matter how many of them I insert... I just need to know the best way of creating an enemy with certain variables that will differ for each of my instances... particularly when some of those variables are in the base class and others are not.
class BaseObject
{
public:
virtual void Render() = 0;
int x;
int y;
};
class Enemy : public BaseObject
{
public:
Enemy() { }
virtual void Render()
{
cout << "Render! Enemy" << endl;
}
typedef std::set<BaseObject *> GAMEOBJECTS;
GAMEOBJECTS g_gameObjects;
int main()
{
g_gameObjects.insert(new Enemy());
g_lootObjects.insert(new Loot());
for(GAMEOBJECTS::iterator it = g_gameObjects.begin();
it != g_gameObjects.end();
it++)
{
(*it)->Render();
}
for(GAMEOBJECTS::iterator it = g_lootObjects.begin();
it != g_lootObjects.end();
it++)
{
(*it)->Render();
}
return 0;
}
Include the arguments in the enemy constructor and Base constructors. You can then use those to initialize the member variables.
class BaseObject
{
public:
BaseObject(int x, int y) : x(x), y(y){ }
virtual void Render() = 0;
int x;
int y;
};
and
class Enemy : public BaseObject
{
public:
Enemy(int x, int y, int foo) : BaseObject(x,y), foo(foo) { }
int foo;
...
};