I'd like to instance multiple object of the same inheritance levels, and for each of these level use the same data. So I think about inheritance and static members of a class.
This is my attempt:
#include <iostream>
class Father
{
public:
static int sValue;
inline int GetValue() { return sValue * 10; }
};
class Child1 : public Father
{
public:
};
class Child2 : public Father
{
public:
};
int Father::sValue = 0;
int main()
{
Child1 child1_1;
Child1 child1_2;
Child2 child2_1;
Child2 child2_2;
child1_1.sValue = 1;
child2_1.sValue = 2;
std::cout << child1_2.GetValue() << std::endl;
std::cout << child2_2.GetValue() << std::endl;
}
In my example both Child1 instances should return 10 with GetValue(), and both Child2 instances should return 20 using GetValue(). Since the function its the same, I don't want to override it for each child (that's why I placed it in Father).
The problem is that also Child1 instances returns 20 calling GetValue().
Thus static is shared across "main" parent, not child.
Since that sValue value is used into GetValue(), its correct to place it here. But I cannot separate static/same data so.
How would you do this?
splrs user has correctly identified your problem and the solution is correct. You need two different functions with two different static objects. You can avoid repeating the code, by using a template:
template<class Child>
struct Father {
static int sValue;
int GetValue() { /* ... */ }
};
struct Child1 : Father<Child1> {};
struct Child2 : Father<Child2> {};
This idiom is known as Curiously recurring template pattern.
Now of course, there is no common parent. If you need that, you can inherit the template from a non-template base:
struct FatherBase {};
template<class Child>
struct Father : FatherBase { /*...*/ };
And, if you need to access the different versions of GetValue from the base, then you need a virtual function:
struct FatherBase {
virtual int GetValue() = 0;
};
template<class Child>
struct Father : FatherBase {
// ...
int GetValue() override { /* ... */ }
};
You're modifying Father::sValue when you call child1_1.sValue = 1; and child2_1.sValue = 2; There's one instance, which belongs to Father, so however you access it (via a method against the classes or the instances) you'll get whatever it was set to prior to the call to GetValue().
If you want a Child1 and a Child2 version then add static members and methods to those classes.
I think the following can be what you're after:
class Father
{
public:
inline int GetValue() { return DoGetValue() * 10; }
void SetValue( int value ) { DoSetValue( value ); }
protected:
virtual int DoGetValue() = 0;
virtual void DoSetValue( int value ) = 0;
};
class Child1 : public Father
{
public:
static int sValue;
protected:
int DoGetValue() override { return sValue; }
void DoSetValue( int value ) override { sValue = value; }
};
class Child2 : public Father
{
public:
static int sValue;
protected:
int DoGetValue() override { return sValue; }
void DoSetValue( int value ) override { sValue = value; }
};
int Child1::sValue = 0;
int Child2::sValue = 0;
int main()
{
Child1 child1_1;
Child1 child1_2;
Child2 child2_1;
Child2 child2_2;
child1_1.SetValue( 1 );
child2_1.SetValue( 2 );
std::cout << child1_2.GetValue() << std::endl;
std::cout << child2_2.GetValue() << std::endl;
}
Related
I want to make something functionally similar to this:
class Base
{
public:
const int ClassID = 1;
}
class Derived1 : public Base
{
public:
const int ClassID = 2;
}
class Derived2 : public Base
{
public:
const int ClassID = 3;
}
But, obviously, you can't override variables. What would be the best way to achieve the same functionality?
(The context for this is a video game where there are different troops, overridden from the same parent "BaseTroop" class. I want each troop to have its own ID that can be retrieved from anywhere)
Thanks in advance!
There is no way to change the default member initialiser in derived classes.
But, there is no need to rely on the default initialiser. You can provide an initialiser in the constructor:
struct Derived1 : Base
{
Derived1(): Base{2} {}
};
struct Derived2 : Base
{
Derived2(): Base{3} {}
};
Add a virtual function, returning the ID. You can also have a static variable or function returning the same ID, in case you want to get it without a class instance. You can also assign the IDs automatically, using CRTP:
#include <iostream>
struct BaseLow
{
virtual int GetId() const = 0;
virtual ~BaseLow() {}
};
namespace impl
{
int &GetIdCounter()
{
static int ret = 0;
return ret;
}
}
template <typename Derived>
struct Base : BaseLow
{
inline static const int id = impl::GetIdCounter()++;
int GetId() const override final
{
return id;
}
};
struct Derived1 : Base<Derived1> {};
struct Derived2 : Base<Derived2> {};
int main()
{
std::cout << Derived1::id << '\n'; // 0
std::cout << Derived2::id << '\n'; // 1
Derived1 d1;
Derived2 d2;
BaseLow *ptrs[] = {&d1, &d2};
for (BaseLow *ptr : ptrs)
std::cout << ptr->GetId() << '\n'; // 0, 1
}
I have a virtual parent class for collecting reports with its associated report struct. The reports should be rendered as a JSON string in the end, so I'm using https://github.com/nlohmann/json to help me with that.
I create different different child classes to generate such reports of the respective child report structs, and the challenge is that each child report may have slightly different fields, but inherit some from the parent. I have the macros that are needed to convert the structs to JSON representation, defined per report type. This is the code so far:
/**
* Compile with nlohmann json.hpp
*/
#include <iostream>
#include <vector>
#include <memory>
#include "json.hpp"
using json = nlohmann::json;
struct Report {
// make abstract
virtual ~Report() {}
std::string type = "main_report";
int foo = 0;
};
struct ChildAReport : public Report {
std::string type = "child_a_report";
int bar = 1;
};
struct ChildBReport : public Report {
std::string type = "child_b_report";
int baz = 2;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ChildAReport, type, foo, bar)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ChildBReport, type, foo, baz)
class Parent {
protected:
std::vector<std::shared_ptr<Report>> reports;
virtual void run() = 0;
virtual std::string get_report() = 0;
};
class ChildA : public Parent {
public:
virtual void run() override
{
ChildAReport r;
r.foo = 1;
r.bar = 2;
reports.push_back(std::make_shared<ChildAReport>(r));
}
std::string get_report() override {
std::shared_ptr<Report> r = reports.back();
std::shared_ptr<ChildAReport> cr = std::dynamic_pointer_cast<ChildAReport>(r);
json r_json = *cr;
return r_json.dump();
}
};
class ChildB : public Parent {
public:
virtual void run() override
{
ChildBReport r;
r.foo = 1;
r.baz = 3;
reports.push_back(std::make_shared<ChildBReport>(r));
}
std::string get_report() override {
std::shared_ptr<Report> r = reports.back();
std::shared_ptr<ChildBReport> cr = std::dynamic_pointer_cast<ChildBReport>(r);
json r_json = *cr;
return r_json.dump();
}
};
int main(int argc, char *argv[])
{
ChildA ca = ChildA();
ca.run();
std::cout << ca.get_report() << std::endl;
ChildB cb = ChildB();
cb.run();
std::cout << cb.get_report() << std::endl;
}
The code is compiled with json.hpp and no further dependencies.
I am expecting this output:
{"bar":2,"foo":1,"type":"child_a_report"}
{"baz":3,"foo":1,"type":"child_b_report"}
Now, in order to actually generate the JSON, I use the get_report() method. I learned that I have to downcast the pointer to the Report struct to the actual ChildA or ChildB struct, because otherwise it won't properly convert to JSON. This is tedious; as you can see, the code is repeated almost verbatim in every possible child class. The run() function is not the problem – here's where all sorts of magic happens, which differs on a per-class basis.
Is there a way I can pull this up to the parent class without having to explicitly specify the type of cast that is to be made before converting to JSON? Ideally this could be inferred depending on the actual type that get_report() is being run on ...
Also an idea could be to make the parent class a templated class, which uses the child report type as template parameter:
#include <iostream>
#include <vector>
#include <memory>
struct Report {
// make abstract
virtual ~Report() {}
std::string type = "main_report";
int foo = 0;
};
struct ChildAReport : public Report {
std::string type = "child_a_report";
int bar = 1;
};
struct ChildBReport : public Report {
std::string type = "child_b_report";
int baz = 2;
};
template<typename REPORT>
class Parent
{
public:
std::string get_report()
{
auto r = reports.back();
return r->type;
}
virtual void run() = 0;
protected:
std::vector<std::shared_ptr<REPORT>> reports;
};
class ChildA : public Parent<ChildAReport> {
public:
virtual void run() override
{
ChildAReport r;
r.foo = 1;
r.bar = 2;
reports.push_back(std::make_shared<ChildAReport>(r));
}
};
class ChildB : public Parent<ChildBReport> {
public:
virtual void run() override
{
ChildBReport r;
r.foo = 1;
r.baz = 3;
reports.push_back(std::make_shared<ChildBReport>(r));
}
};
int main()
{
auto ca = ChildA();
ca.run();
std::cout << ca.get_report() << std::endl;
auto cb = ChildB();
cb.run();
std::cout << cb.get_report() << std::endl;
return 0;
}
Edited answer, because pure virtual method is not needed anymore
Update for your comment:
Create a base class (interface) for parent to be used in your example:
class IGrandparent
{
public:
virtual std::string get_report() = 0;
virtual void run() = 0;
};
template<typename REPORT>
class Parent : public IGrandparent
{
public:
std::string get_report() override
{
auto r = reports.back();
return r->type;
}
protected:
std::vector<std::shared_ptr<REPORT>> reports;
};
int main()
{
std::unique_ptr<IGrandparent> childAInDisguise = std::make_unique<ChildA>();
std::unique_ptr<IGrandparent> childBInDisguise = std::make_unique<ChildB>();
childAInDisguise->run();
std::cout << childAInDisguise->get_report() << std::endl;
childBInDisguise->run();
std::cout << childBInDisguise->get_report() << std::endl;
return 0;
}
One thing you can do it's to have a template in the base class Parent but this implies to remove the virtual keyword so Parent class won't be a interface anymore. This it's only the easy way to do it for making get_report less tedious, if Parent class has to be an interface this solution is not valid.
If this helps you it would be like this:
class Parent {
protected:
std::vector<std::shared_ptr<Report>> reports;
virtual void run() = 0;
template <class T>
std::string get_report_base()
{
std::shared_ptr<Report> r = reports.back();
std::shared_ptr<T> cr = std::dynamic_pointer_cast<T>(r);
json r_json = *cr;
return r_json.dump();
}
};
And the children will cal get_report_base:
class ChildA : public Parent {
public:
virtual void run() override
{
ChildAReport r;
r.foo = 1;
r.bar = 2;
reports.push_back(std::make_shared<ChildAReport>(r));
}
std::string get_report() {
return get_report_base<ChildAReport>();
}
};
I have a Base class composed of another class (let's call it Component). If I inherit from the Base class, is it possible to add functionality to the Component class (assumming you can't modify the Base code)? I basically want a 'Derived::Component::foo' function.
#include <iostream>
class Base
{
public:
void Print() { std::cout << c.data; }
class Component
{
public:
int data;
};
Component c;
};
class Derived : public Base
{
private:
void Component::foo(int value)
{
this->data = value;
}
public:
void bar(int value)
{
this->c.foo(value);
}
};
int main() {
Derived d;
d.bar(4);
d.Print();
}
This code gives the following error under G++ 4.8 on Ubuntu:
error: cannot define member function ‘Base::Component::foo’ within ‘Derived’
[..] add functionality [..] (assumming you can't modify the Base code) [..]
Depending on how the actual base class in question looks like, you could try to get by with simple subclassing of the Component:
/* using struct to have public accessibility */
struct Base {
struct Component {
int data;
virtual ~Component() {} // ABSOLUTELY NECESSARY
};
std::unique_ptr<Component> component; // ABSOLUTELY NECESSARY
void print(void) {
std::cout << component->data << endl;
}
};
/* The decorated component, with the additional functionality */
struct DecoratedComponent : public Base::Component {
void set(int d) {
data = d;
}
};
Then, assuming there's someway to set the component, you need to pass in your decorated component (note: If there's state to be preserved, you could also wrap an Component instance in your decorated component class, making this a real usage of the Decorator Pattern):
Base the_base;
auto the_component = std::make_unique<DecoratedComponent>();
// Inject the decorated component
the_base.component = the_component;
the_component.set(42);
the_base.print(); // 42
This will only work if the base uses either a reference or some sort of pointer to store/access it's component. Additionally, if the base is managing the lifetime of the component, the Component must have a virtual destructor.
You need to declare the foo function in the Component class. And then define it inside the Component itself:
#include <iostream>
class Base
{
public:
void Print() { std::cout << c.data; }
class Component
{
public:
int data;
void foo( int value )
{
data = value;
}
};
Component c;
};
class Derived : public Base
{
private:
public:
void bar(int value)
{
c.foo(value);
}
};
int main() {
Derived d;
d.bar(4);
d.Print();
}
Or outside of all of the classes:
#include <iostream>
class Base
{
public:
void Print() { std::cout << c.data; }
class Component
{
public:
int data;
void foo( int value );
};
Component c;
};
void Base::Component::foo(int value)
{
data = value;
}
class Derived : public Base
{
private:
public:
void bar(int value)
{
c.foo(value);
}
};
int main() {
Derived d;
d.bar(4);
d.Print();
}
This question already has answers here:
Overriding static variables when subclassing
(8 answers)
Closed 8 years ago.
I want each class to have its own static code, which can be requested from each object. I am thinking of this, but it doesn't seem to work:
#include <iostream>
class Parent {
protected:
static int code;
public:
int getCode();
};
int Parent::code = 10;
int Parent::getCode() {
return code;
}
class Child : public Parent {
protected:
static int code;
};
int Child::code = 20;
int main() {
Child c;
Parent p;
std::cout << c.getCode() << "\n";
std::cout << p.getCode() << "\n";
return 0;
}
It outputs:
10
10
yet I expect
20
10
You have to make the 'getCode()' function as virtual and have to implement every time as following codes:
class Parent {
protected:
static int code;
public:
virtual int getCode() { return code; }
};
int Parent::code = 10;
class Child : public Parent {
protected:
static int code;
public:
virtual int getCode() { return code; }
};
int Child::code = 20;
int main()
{
Child c;
Parent p;
std::cout << c.getCode() << "\n";
std::cout << p.getCode() << "\n";
return 0;
}
class Parent {
public:
virtual int getCode();
// Looks like a variable, but actually calls the virtual getCode method.
// declspec(property) is available on several, but not all, compilers.
__declspec(property(get = getCode)) int code;
};
class Child : public Parent {
public:
virtual int getCode();
};
int Parent::getCode() { return 10; }
int Child::getCode() { return 20; }
int main() {
Child c;
Parent p;
std::cout << c.code << "\n"; // Result is 20
std::cout << p.code << "\n"; // Result is 10
return 0;
}
Why use the member variable at all?
class Parent {
public:
static int getCode();
};
int Parent::getCode() {
return 10;
}
class Child : public Parent {
public:
static int getCode();
};
int Child::getCode() {
return 20;
}
Instead of one static member per class, you have one member function per class. Plain and simple.
Your problem:
In the parent class, you don't declare your getCode function as virtual.
So, whenever you call it with a class that inherits from your parent class,
it will just return the int code from the parent class.
To fix this:
First, declare the getCode function as virtual in your parent class.
Second, write another getCode function in your inherited class and return
the int code from the inherited class
I need a base class that gives me primitive type of data's pointer. I add a function in it. I derived types of class. I used void * to support all primitive types as a return type but it is like old C days. It is not good for OOP. Does one have an suggestion to do in a proper way in OOP?
#include <iostream>
class base {
public:
virtual void *getPtr() = 0;
virtual ~base() {};
};
class derivedAType : public base {
protected:
int _i;
public:
derivedAType(int i): _i(0) { _i = i; };
virtual ~derivedAType() {}
virtual void *getPtr() {
return static_cast<void *>(&_i);
}
};
class derivedBType : public base {
protected:
short _s;
public:
derivedBType(short s): _s(0) { _s = s; };
virtual ~derivedBType() {}
virtual void *getPtr() {
return static_cast<void *>(&_s);
}
};
int main()
{
base *b1 = new derivedAType(1203912);
base *b2 = new derivedBType(25273);
std::cout << "b1 : " << *(static_cast<int *>(b1->getPtr()))
<< "\nb2 : " << *(static_cast<short *>(b2->getPtr()))
<< std::endl;
delete b2;
delete b1;
return 0;
}
Make the base class a template class with the data type as the template variable
template<typename DataType>
class base {
virtual DataType* getPtr() = 0;
//...
};
and
class derivedAType : public base<int>
But this changes base class to a template class which means you cant store them together, base<int> is different from base<short>
If this isnt acceptable, the other options is just a tad bit cleaner than your code but abt the same, refer to this question. Basically derived class return types can reflect their true type and i think it should get automatically converted to void*, so you dont have to manually cast the pointer.
Not sure about your problem. But maybe a double callback can help:
class Callback {
public:
virtual void do_int( int i ) const = 0;
virtual void do_short( short s ) const = 0;
/* ... */
}
class base {
public:
virtual void do_stuff(const Callback & c); /* will need a more telling name */
virtual ~base() {};
};
class derivedAType : public base {
protected:
int _i;
public:
derivedAType(int i): _i(0) { _i = i; };
virtual ~derivedAType() {}
virtual void do_stuff(const Callback & c) {
c.do_int( _i );
}
};
class derivedBType : public base {
protected:
short _s;
public:
derivedBType(short s): _s(0) { _s = s; };
virtual ~derivedBType() {}
virtual void do_stuff( const Callback & c) {
c.do_short( _s );
}
};
class print_callback : public Callback {
public:
virtual void do_int( int i ) const { std::cout << i; }
virtual void do_short( short s ) const { std::cout << s; }
}
int main() {
base *b1 = new derivedAType(1203912);
base *b2 = new derivedBType(25273);
std::cout << "b1 : ";
b1->do_stuff(print_callback());
std::cout << "\nb2 : ";
b2->do_stuff(print_callback());
std::cout << std::endl;
delete b2;
delete b1;
return 0;
}
Of course you can simplify this by just storing the created print callback, and using it twice.