I'm working on a game and I want to make a base Actor class that holds Stat values that are shared among a variety of Actor types, but I'm having an issue understanding how I can accomplish this without having the base class having a different Stats variable than the actor types...
This is exactly what I have made right now (as shown in the code)... However, I want to somehow make the BaseActor "stats" type become either a PlayerStats or a MonsterStats object when it is created...This way the PlayerActor and MonsterActor no longer need the different "monster_stats" and "player_stats" objects as they inherit the correct type from BaseActor. Is this possible? I'm thinking it can be done through templates, but I'm not too versed in those.
class BaseStats {
public:
int defense;
private:
};
class MonsterStats : public BaseStats {
public:
int drop_rate;
private:
};
class PlayerStats : public BaseStats {
public:
int attack_power;
private:
};
class BaseActor {
public:
BaseStats stats;
private:
};
class MonsterActor : public BaseActor {
public:
MonsterStats monster_stats;
private:
};
class PlayerActor : public BaseActor {
public:
PlayerStats player_stats;
private:
};
Have PlayerStats and MonsterStats derive from BaseStats. Have the constructor of each derived BaseActor allocate the stats with:
MonsterActor::MonsterActor()
{
m_stats = make_shared<MonsterStats>();
}
and have
std::shared_ptr<BaseStats> m_stats;
in the base class.
Look for Jeffrey's answer for a better way. But since you wanted to do this through templates (which is not recommended): -
template <typename T>
class BaseActor {
public:
T stats;
};
class MonsterActor : public BaseActor<MonsterStatus> {
public:
};
class PlayerActor : public BaseActor<PlayerStatus> {
public:
};
Related
Context: I'm doing some internal cleanup to move away from large & unwieldy data structures to more well-defined data structures.
Current
I have a class that does something like this:
class Base {
public:
virtual int DoStuff(BigType input);
};
Calling code:
std::vector<Base*> bases;
BigType input;
for (const auto& base : bases) {
base.DoStuff(input);
}
Child classes currently look like this:
class Child : public Base {
int DoStuff(BigType input) const override {
// do stuff
}
};
Attempted
I added an intermediate interface:
template <typename SmallType>
class FocusedBase : public Base {
public:
int DoStuff(BigType input) const override {
return DoStuff(SmallType(input));
}
virtual int DoStuff(SmallType input);
};
Child classes now look like this. Note that SmallType may differ across child classes:
class Child : public FocusedBase<SmallType> {
int DoStuff(SmallType input) {
// do stuff
}
};
Calling code remains the same.
Issue
I'd like to have new classes inherit from FocusedBase only, not Base. Any thoughts on how to do so?
If you want to disallow inheriting from Base directly you can make Base::Base() private and make FocusedBase a friend:
struct Base {
private:
Base() = default;
friend class FocusedBase;
};
struct FocusedBase : Base {};
struct Foo : Base {};
struct Bar : FocusedBase {};
int main() {
//Foo f; // error
Bar b; // ok
}
class Class1 {
Class1() { Class2::counter++;}
}
class Class2: public Class1 {
public:
static int counter;
}
The above is an example of what I am trying to do. I am trying to use a static variable of a subclass in the superclass but that gives me a compiler error since Class1 is initialized first and when the compiler reaches the Class2::counter++; it has not initialized Class2 yet and therefore I get a "Class2 has not been declared" error. How can I fix this? Do I need to change my logic completely?
From a OOP perspective a parent class is not able to access to a child field or property, it should the opposite way a child accessing to a parent field or property. I'm wondering whyeyou need to access tora child field from the parent? If you provide more details what you are trying to achieve the best solution will be provided by someone.
You could just pass a reference to your counter to the base class:
class Class1 {
public:
Class1(int& counter) { ++counter; }
};
class Class2: public Class1 {
public:
static int counter;
Class2() : Class1(counter) { }
};
int Class2::counter = 0;
You may put definition of constructor Class1 after Class2 definition:
class Class1 {
public:
Class1();
};
class Class2: public Class1 {
public:
static int counter;
};
int Class2::counter = 0;
Class1::Class1() { Class2::counter++;}
Live demo
A rule of thumb: base classes don't access child class members or methods.
If the base class needs something from a child class, declare an abstract virtual function in the base class for the child to implement.
Or move the common data members or methods into the base class.
In your case:
class Base
{
virtual void increment_counter(void) = 0;
void my_method(void)
{
increment_counter();
}
};
class Child : public Base
{
int counter;
void increment_counter(void)
{
++counter;
}
};
Simply define the constructor of class Class1 after the definition of Class2.
class Class1 {
public:
Class1();
}
class Class2: public Class1 {
public:
static int counter;
}
Class1::Class1() { Class2::counter++;}
Do not forget to define the static data member of Class2.:)
If you want to get freaky with templates, this sounds a possible use for the curiously recurring template pattern. For example:
template <typename T>
class CRTBase
{
CRTBase() { T::counter++; }
};
class CRTDerived : public CRTBase<CRTDerived>
{
public:
static int counter;
};
int CRTDerived::counter = 0;
In C++11, I can expose an enumerator which is protected in a base class, to users of a derived class, as follows:
class Base
{
protected:
enum Waldo { hidden, found };
};
class Derived : public Base
{
public:
using Base::Waldo;
}
void foo()
{
Derived::Waldo w = Derived::Waldo::found;
}
Unfortunately, in C++03, Derived::Waldo::found is illegal, and Derived::found is met with 'Base::Waldo Base::found' is protected within this context.
I could work around that by also writing a using for each enumerator:
class Derived : public Base
{
public:
using Base::Waldo;
using Base::hidden;
using Base::found;
}
void foo()
{
Derived::Waldo w = Derived::found; // works in C++03
}
but this can be really tedious to do if the enumerator has many enumerators. Is there a way to pull off this enum-exposing in C++03 without this tedium?
SCNR!
struct Wrap
{
enum Waldo { hidden, found };
};
class Base : protected Wrap
{
};
class Derived : public Base
{
public:
using Base::Wrap;
};
void foo()
{
Derived::Wrap::Waldo w = Derived::Wrap::found;
}
Edit: Or you put it inside:
class Base
{
protected:
struct Wrap
{
enum Waldo { hidden, found };
};
};
class Derived : public Base
{
public:
using Base::Wrap;
};
void foo()
{
Derived::Wrap::Waldo w = Derived::Wrap::found;
}
Well, I think there are lots of different ways to do this, depending on what you want to do with the enum. Here is one:
struct WaldoStates
{
enum States{hidden, found};
};
class Base
{
public:
typedef WaldoStates Waldo;
};
class Derived : public Base
{
};
void foo()
{
WaldoStates::States state = Derived::Waldo::found;
}
Now, this is good if simply want the states to be accessible with something like myClass::Waldo::hidden in any class of the inheritance tree. If you want to be able to set different states for some of the derived classes, you may want to do something like this instead:
struct WaldoStates
{
typedef int State;
};
struct DefaultWaldoStates : public WaldoStates
{
enum States{hidden, found};
};
struct OtherWaldoStates : public WaldoStates
{
enum States{stillHidden, alreadyFound};
};
class Base
{
public:
typedef DefaultWaldoStates Waldo;
};
class Derived : public Base
{
};
class OtherDerived : public Base
{
public:
typedef OtherWaldoStates Waldo;
};
void foo()
{
WaldoStates::State state0 = Derived::Waldo::found;
WaldoStates::State state1 = OtherDerived::Waldo::alreadyFound;
}
I have a base class called Number. Class One and Two are derived from Number.
Now I define another class Three, where I need to access individual base classes from the multiple inheritance:
class Number{
protected:
int val;
public:
Number(){
val=0;
}
void Add(Number n){//Receives another Number class instance and add the value
val+=n.val;
}
};
//class One derived from Number
class One:public Number{
public:
One(){
cal=1;
}
};
//class two derived from Number
class Two:public Number{
public:
Two(){
val=2;
}
};
class Three:public One,public Two{
public:
Three(){
Two::Add(One);//--How can i pass instance of class One Here
}
};
I tried One::Number and Two::Number, but no use.
There are a few problems, first val is private and so that needs to be made protected. Next you have a diamond of death so you need to virtual public for One and Two. You also are trying to call Add using a type but you need an instance of each class:
class Number{
protected:
int val;
public:
Number(){
val=0;
}
void Add(Number& n){//Receives another Number class instance and add the value
val+=n.val;
}
};
//class One derived from Number
class One:virtual public Number{
public:
One(){
val=1;
}
};
//class two derived from Number
class Two:virtual public Number{
public:
Two(){
val=2;
}
};
class Three: public One, public Two{
public:
Three()
{
Two t1 ;
Add(t1 );//--How can i pass instance of class Two Here
}
};
It could be argued that using protected data is bad but it depends on your case but to be complete it is also a choice to keep val a private data member and use a protected constructor and that would look like this:
class Number{
private:
int val;
protected:
Number( int n ) : val(n) {}
public:
Number(){
val=0;
}
void Add(Number& n){//Receives another Number class instance and add the value
val+=n.val;
}
};
class One: virtual public Number{
public:
One() : Number( 1 ) {
}
};
class Two: virtual public Number{
public:
Two() : Number(2) {
}
};
This should work:
Two::Add(*(One*)this);
You need to create objects of the respective types.
class Three : public One, public Two
{
public:
Three()
{
Add(One());
Add(Two());
}
};
But I don't see why you need MI here. Inheriting from Number would be sufficient.
The problem is not just the syntax. But what exactly are you trying to do?
You can. But where is the instance of One declared? you have to declare it first. Remember Two::Add(One); is not a declaration rather a call statement.
What you are doing is equivalent to let's say
process_number(One);
Where process number is a function.
I'm looking for a clean way of doing this since a long time. In my problem, there exist 3 classes not sharing any parent in common but each having some methods with the same name (A.doSomething, B.doSomething, C.doSomething). Hence, having the same function signature, class D inheriting from A and using method doSomething() will "look the same" to E inheriting from B or C .
Here is a sketch of what I'd like to be able to do:
class Base {
public:
void myMethod(void) { doSomething(); }
};
class Independent {
public:
doSomething();
};
clase Derived : public Base : public Independent {
(...)
};
int main(void) {
Derived *derivedObject = new Derived();
derivedObject->myMethod();
}
In this problem, object of type "Independent" is provided by a library that I cannot change. I would like to define a base class that uses methods that are going to be inherited later on. I couldn't find a proper way of doing this using virtual inheritance without causing ambiguous compiling.
You've got a nasty situation there. One solution to this would be using the Curiously Recurring Template Pattern to perform the inheritance at compile-time, like this:
template <typename D>
class Base {
public:
void myMethod(void) { static_cast<D*>(this)->doSomething(); }
};
class Independent {
public:
void doSomething();
};
clase Derived : public Base : public Independent {
/*...*/
};
int main(void) {
Derived *derivedObject = new Derived();
derivedObject->myMethod();
}
Alternatively, you could choose to put a middleman class in between to forward to Independent (I assume you have many classes deriving from the same Base and Independent, and just don't want to have to do this for each class).
template <typename D>
class Base {
private:
virtual void doSomethingImpl();
public:
void myMethod(void) { doSomethingImpl(); }
};
class Independent {
public:
void doSomething();
};
class IndependentWrapper : public Base : public Independent {
private:
void doSomethingImpl() { Independent::doSomething(); }
};
clase Derived : public IndependentWrapper {
/*...*/
};
int main(void) {
Derived *derivedObject = new Derived();
derivedObject->myMethod();
}