Avoiding object-slicing in vector<shared_ptr<Base>> - c++

I'm storing my game's states (collections of entities, essentially) in a vector of shared pointers. When adding states to the vector, the derived part of the states is lost and they revert to the base state class. It all compiles fine, but when I query the states' names, they all come back as DEFAULT_STATE_NAME. I've read plenty of information about object splitting, but I cannot see what is going wrong here.
State.hpp
class State {
protected:
Game &game;
public:
typedef shared_ptr<State> Pointer;
static const StateName name = DEFAULT_STATE_NAME;
explicit State(Game &game_) : game(game_) ;
virtual ~State() {}
};
Example derived state class
namespace {
class Overworld : public State {
public:
static const StateName name;
Overworld(Game &game) : State(game) {}
};
const StateName Overworld::name = OVERWORLD;
}
Game.hpp
class Game {
private:
vector<State::Pointer> states;
public:
void addState(const State::Pointer &state) {
if(!state)
throw "invalid state error";
states.push_back(state);
}
// ...
}

In order to access member methods of a derived class through a pointer (or reference) to its base class, you must use polymorphism (which you didn't). For example
struct Base {
virtual string name() const { return "Base"; }
};
struct Derived : Base {
string name() const override { return "Derived"; }
};
const Base*ptr = new Derived;
assert(ptr->name()=="Derived");
Such polymorphism only works with non-static member methods, not with data members nor with static member functions. In your case, there is no polymorphism and hence Base::name remains, well, Base::name.
In your particular case, there are two other possible solutions, though. First, you can use RTTI, though this is generally frowned upon. Another option is to keep the name as a data member in Base and pass it in at construction:
struct Base {
const string name = "Base";
Base() = default;
protected:
Base(string const&n)
: name(n) {}
};
struct Derived : Base {
Derived()
: Base("Derived") {}
};
const Base*ptr = new Derived;
assert(ptr->name=="Derived");
when there is no polymorphism (and hence no virtual table and additional indirection) involved, but at the cost of a data member name.

name in State and name in Overworld are two completely independent class-variables. They are not part of any instances state, nor can you directly query an instance for class-variables, as those cannot be virtual. In order to Access class-variables polymorphically, you need to use a virtual function.
Add such a member-function to State, and don't forget overriding it in derived classes as needed. Or, you know, you could just use the languages standard RTTI using typeid.

Related

Member of derived by pointer to base, static_cast, crtp, removing templates

Looking for: accessing member of a derived class from a pointer to base.
Reductio ad absurdum:
class Base
{
public:
int member_of_base;
};
class Derived : public Base
{
public:
int member_of_derived;
};
I'm currently using templates:
template <class T>
class Client
{
T* data; // T is Base or Derived
};
There are few levels of composition in the class hierarchy, so I have to carry the template type parameter through all of the hierarchy. What is the best approach to overcome this?
Obviously I cannot access the member of Derived via a pointer to Base, i.e:
Base* foo = new Derived();
foo->member_of_derived; // no go
Thus, I'm using:
Client<Base>
Client<Derived>
I'm trying to come up with a solution that works without the templates. Options that I know would work:
void* //plain old C and casting as necessary, they're all pointers
(as in memory addresses) in the machine
static_cast<Derived*>(pointer_to_base); //type safe at compile time.
wrapping the cast in a Client's template method (not to be confused with a design pattern here)
The last option seems to be the most "elegant", i.e:
template <class T>
T* get_data() const { return static_cast<T*>(data); }
However, looking here and there tells me there might exist a way unknown to me.
I saw CRTP, but that brings me back to templates, which is the original thing I want to go without.
What are the ways, or popular approaches, to achieve such a goal?
The real code uses shared_ptr, weak_ptr and enable_shared_from_this with weak_from_this. I'm looking for a type safe "polymorphic member" access.
EDIT: they're not just "ints". They can be totally different types, as in protobuf in base and Json::Value in derived. And I'm trying to use the pointers to Base/Derived, which in turn would give me access to their respective members.
A virtual getter can solve the issue for you; as data types differ, you might pack them into a std::variant.
class Base
{
// having private members probably is more appropriate
int member_of_base;
public:
using Data = std::variant<int, double>;
virtual ~Base() { } // virtual functions -> have a virtual destructor!
virtual Data getMember() // or just "member", if you prefer without prefix
{
return member_of_base;
}
};
class Derived : public Base
{
double member_of_derived;
public:
Data getMember() override
{
return member_of_derived;
}
};
std::unique_ptr<Base> foo = new Base();
foo->getMember(); // member_of_base;
std::unique_ptr<Base> bar = new Derived();
bar->getMember(); // member_of_derived;
Admitted, not yet totally without templates, std::variant is one, but I suppose in that form it is acceptable...
There are some issues with, though:
Accessing the value is not the simplest, you might consider visit function for.
More severe: Base class (or wherever else you define the variant to be used) needs to be aware of all types that might be in use, adding a new type will force to recompile all other classes.
It has the smell of bad design. Why should it be necessary for a derived class to return something different than the base that shall serve the same purpose, though???
If you can delegate the work to be done to the classes themselves, you get around all these problems:
class Base
{
int member_of_base;
public:
virtual ~Base() { }
virtual void doSomething()
{
/* use member_of_base */
}
};
class Derived : public Base
{
double member_of_derived;
public:
void doSomething() override
{
/* use member_of_derived */
}
};
The latter would be the true polymorphic approach and normally the way to go; whereas the sample above returns void, you might just do all the calculations necessary in base and derived classes until you finally get to some common data type and return this one. Example:
class Base
{
int64_t m_balance; // in 100th of currency in use
public:
virtual ~Base() { }
virtual int64_t balance()
{
return m_balance;
}
};
class Derived : public Base
{
long double m_balance; // arbitrary values in whole currency entities
public:
int64_t balance() override
{
// calculate 100th of currency, correctly rounded:
return std::llround(m_balance * 100);
}
};
Admitted, I doubt pretty much representing a balance in double (even if long) is a good idea (issues with rounding, precision, etc)...

Making parent class members unmodifiable for each derived class

I'm wondering how can I make unmodifiable a parent class member which will be different for each derived class.
My code now assigns its value correctly (depending on the Child class that calls the parent class' constructor), but m_type can be easily modified (in myfunction, for example) and that's what I'd like to avoid.
#include <iostream>
enum Piece_type{ king=1, queen=3, rook=3, bishop=4, knight=5, pawn=6};
class Piece
{
protected:
Piece_type m_type; // static Piece_type m_type; <- doesn't work
Piece(Piece_type ex): m_type(ex) {}
};
class Pawn: public Piece
{
public:
Pawn():Piece(pawn) {} // To initialise m_type as pawn for all my Pawn objects
void myfunction()
{
std::cout<<"My piece type is "<< m_type<<std::endl;;
m_type= knight; // This is the assignation I want to avoid happening
std::cout<<"My new piece type i "<<m_type<<std::endl;
}
};
My question is related to this one, but inheritance doesn't seem to make possible to declare a static variable and define its value through a member initializer.
I've found how to call the parent/base class constructor from the Child class in this question.
Thanks in advance,
Eduardo
Edit
I've slightly modified it so that not to confuse anyone, because const does work where I said it didn't.
Well, you didn't fall into the usual mistake of trying to use const member variables without a member initializer list, so const is all you need really:
class Piece
{
protected:
Piece_type const m_type;
Piece(Piece_type ex) : m_type(ex) { }
};
class Pawn : public Piece
{
public:
Pawn() : Piece(pawn) { }
void myfunction()
{
// m_type = knight; // Compile-time error
}
};
They only ways to prevent a derived type from modifying it's parent's members is to make those members private or const. Since you can't make the member const the only other way would be to declare the member private and adding a protected accessor method such as :
Piece_type get_type() const
{
return m_type;
}
This way, derived classes can call get_type() to know m_type's value but can't access it directly, preventing them from writing to it.

QSharedData and inheritance

I'm trying to make a type system while using QSharedData. The idea is simple, there will be a number of different data types, each of which is going to be derived from the base abstract class. I want to use QSharedData to store the actual data in each of them, but each of the derived classes is going to have different data stored inside. I'm trying to make the most basic example now, and having some troubles.
Let's say these are my base pure virtual classes:
class cAbstractData: public QSharedData
{
public:
cAbstractData(){ }
virtual int type() = 0;
};
class cAbstractValue
{
public:
cAbstractValue(){ }
virtual int type() = 0;
protected:
QSharedDataPointer<cAbstractData>data_;
};
Now let's say I want to make a class for representing a single value (as a minmalistic example that is). I'm deriving the cAtomicValue from the base value class, and I am also deriving a data class to hold the value:
class cAtomicData:public cAbstractData
{
public:
cAtomicData() { value_ = 0; }
int type(){ return 1; }
QVariant value_;//the actual value
};
class cAtomicValue:public cAbstractValue
{
public:
cAtomicValue() {
data_ = new cAtomicData;//creating the data object.
}
int type(){ return 1; }
};
Now at this stage it works just fine, and in the debugger I can see the right pointer type. But now I want to add a function for setting and getting the value, and I fail to understand how to do it. Let's take the setter as an example. To set the value, we must access the value_ member of cAtomicData class through the data_ member of the cAtomicValue class. However since the data_ holds a base-class pointer (cAbstractData), I'll have to cast it to the right type (cAtomicData) somehow. I tried doing this:
template<class T> void set( T value )
{
static_cast<cAtomicData*>(data_.data())->value_ = value;
}
it obviously doesn't work, because it called detach() and tries to make a copy of the base class which it can't since the base class is pure virtual. Then I tried to cast the pointer itself:
static_cast<cAtomicData*>(data_)->value_ = value;
but I'm getting an invalid static_cast ... error.
How do I do it, and am I even doing it the right way fundamentally?
You can switch to QExplicitlySharedDataPointer instead of QSharedDataPointer. In that way detach() won't be called whenever you're trying to obtain a non-const pointer to the cAbstractData object, which includes casting the QExplicitlySharedDataPointer<cAbstractData> object to a QExplicitlySharedDataPointer<cAtomicData> object. However, you will need to call detach() manually every time you want to make a modification to the cAbstractData if you are going to use copy-on-write. Maybe you can write a wrapper class to perform the detaching for you.
This method may be prefered over using QSharedPointer, since a QExplicitlySharedDataPointer is the same size as a normal pointer (and hence keeps binary compability) while a QSharedPointer is twice the size (see this blog entry).
Edit: Note that the cast from QExplicitlySharedDataPointer<cAbstractData> to QExplicitlySharedDataPointer<cAtomicData> is static, so you will have to guarantee that the object that is referenced actually is an object of the type cAtomicData (or of a subclass), or the behavior when using the pointer might be undefined.
I had a similar problem in my application and here is how I solved it. I have a BaseClass that is implemented using the Pimpl idiom and QExplicitlySharedDataPointer pointing to BaseClassPrivate. This class is inherited by DerivedClass whose private member is a DerivedClassPrivate inheriting BaseClassPrivate.
BaseClassPrivate has one float member named baseParam and DerivedClassPrivate has another float parameter named derivedParam.
I solved this problem doing the following :
Define a protected constructor BaseClass(BaseClassPrivate* p)
This is used to instantiate new derived classes with a pointer to DerivedClassPrivate
Define a virtual clone() method in both BaseClassPrivate and DerivedClassPrivate
This method is called to correctly copy the private class whenever a deep copy is needed. So, instead of calling 'QExplicitlySharedDataPointer::detach()', we check if the QSharedData reference counter is greater than 1, and then we call clone. Please note that QSharedData::ref is not in the documentation so this can change anytime (even though it seems unlikely to happen soon).
Static cast the d pointer in DerivedClass
I find it convenient to define a private dCasted() function.
To test this the virtual function foo() is introduced in BaseClassPrivate and DerivedClassPrivate, which returns either baseParam or derivedParam accordingly.
Here is the code :
BaseClass.h
class BaseClass
{
public:
BaseClass() : d(new BaseClassPrivate()) {}
BaseClass(const BaseClass& other) : d(other.d) {}
BaseClass& operator =(const BaseClass& other) {d = other.d; return *this;}
virtual ~BaseClass() {}
float baseParam() const {return d->baseParam;}
void setBaseParam(float value) {
detach(); // instead of calling d.detach()
d->baseParam = value;
}
float foo() const {return d->foo();}
protected:
BaseClass(BaseClassPrivate* p) : d(p) {}
void detach() {
// if there's only one reference to d, no need to clone.
if (!d || d->ref == 1) return; // WARNING : d->ref is not in the official Qt documentation !!!
d = d->clone();
}
QExplicitlySharedDataPointer<BaseClassPrivate> d;
};
DerivedClass.h
class DerivedClass : public BaseClass
{
public:
DerivedClass() : BaseClass(new DerivedClassPrivate()) {}
float derivedParam() const {return dCasted()->derivedParam;}
void setDerivedParam(float value) {
detach(); // instead of calling d.detach();
dCasted()->derivedParam = value;
}
private:
DerivedClassPrivate* dCasted() const {return static_cast<DerivedDataPrivate*>(d.data());}
};
BaseClassPrivate.h
class BaseClassPrivate : public QSharedData
{
public:
BaseClassPrivate() : QSharedData(), baseParam(0.0) {}
BaseClassPrivate(const BaseClassPrivate& other) :
QSharedData(other), baseParam(other.baseParam) {}
virtual ~BaseClassPrivate() {}
float baseParam;
virtual float foo() const {return baseParam;}
virtual BaseClassPrivate* clone() const {
return new BaseClassPrivate(*this);
}
};
DerivedClassPrivate.h
class DerivedClassPrivate : public BaseClassPrivate
{
public:
DerivedClassPrivate() : BaseClassPrivate(), derivedParam(0.0) {}
DerivedClassPrivate(const DerivedClassPrivate& other) :
BaseClassPrivate(other), derivedParam(other.derivedParam) {}
float derivedParam;
virtual float foo() const {return derivedParam;}
virtual BaseClassPrivate* clone() const {
return new DerivedClassPrivate(*this);
}
};
Now, we can do things such as :
Call virtual functions :
DerivedClass derived;
derived.setDerivedParam(1.0);
QCOMPARE(derived.foo(), 1.0); // proving that DerivedClassPrivate::foo() is called
Make copies from DerivedClass to BaseClass correctly :
BaseClass baseCopy = derived;
QCOMPARE(baseCopy.foo(), 1.0); // proving that DerivedClassPrivate::foo() is called
// even after copying to a BaseClass
Make copies from BaseClass to BaseClass respecting the original class and also make a copy-on-write correctly :
BaseClass bbCopy(baseCopy); // make a second copy to another BaseClass
QCOMPARE(bbCopy.foo(), 1.0); // still calling DerivedClassPrivate::foo()
// copy-on-write
baseCopy.setBaseParam(2.0); // this calls the virtual DerivedClassPrivate::clone()
// even when called from a BaseClass
QCOMPARE(baseCopy.baseParam(), 2.0); // verify the value is entered correctly
QCOMPARE(bbCopy.baseParam(), 1.0); // detach is performed correctly, bbCopy is
// unchanged
QCOMPARE(baseCopy.foo(), 1.0); // baseCopy is still a DerivedClass even after detaching
Hope this helps
I don't see any way to achieve what you're attempting here. As you've discovered, QSharedDataPointer needs to be templated on the actual type it contains.
You could make your base class a template, e.g.
template<class T>
class cAbstractValue
{
public:
cAbstractValue(){ }
virtual int type() = 0;
protected:
QSharedDataPointer<T> data_;
};
But I'm not sure I see what benefit you would get from that.
Since Qt 4.5 you can implement the ::clone() function for your type:
This function is provided so that you may support "virtual copy constructors" for your own types. In order to so, you should declare a template-specialization of this function for your own type, like the example below:
template<>
EmployeeData *QSharedDataPointer<EmployeeData>::clone()
{
return d->clone();
}
In the example above, the template specialization for the clone() function calls the EmployeeData::clone() virtual function. A class derived from EmployeeData could override that function and return the proper polymorphic type.
This function was introduced in Qt 4.5.
I've done so and it works.
Either your abstract base class and all derived classes need to implement a virtual BaseClass* clone() function you'd call from QSharedDataPointer::clone() or you need some other method (e.g. factory) to create a new instance with the same content as d.

Is it possible to declare a virtual static constant value in a C++ class?

I'd like to have a base class that has a constant field (like an unique ID associated with the class that can't be modified after compile time). So far the static const declaration would be just fine. Now, I'd like to inherit this base class and make sure that the children of this class do have the same field, but with their own values. How can I do this?
Let's say, I'd like to have a base class called Base with an ID field that holds the int value of 0. Then, I'd like to have the classes A, B and C, all of them being public children of Base and I'd like to make sure that these children would also have the ID fields with the respective values of 1, 2 and 3 (by 'making sure', I mean something like getting a compiler error if they don't have a ID explicitly declared).
If I could manage to build this scenario, my expectation would be that asking for the ID field of a Base* pointer, I should get different values depending whether the pointer was created as new A(), new B() or new C().
My guess would be to declare ID as virtual static const, which of course doesn't make sense and gives a compiler error.
But then what can I do to achieve the described result? (The only thing that I could imagine would be to declare ID as a virtual function returning an integer and then hard-code the value into the function body, but I'm looking for something more elegant.)
Thank you in advance!
A static method cannot be virtual, and no data members can be virtual.
But you can hide static fields in derived classes and use a virtual method to return them.
class A
{
public:
static const int ID = 0;
virtual int getID() { return A::ID; }
};
class B : A
{
public:
static const int ID = 1;
virtual int getID() { return B::ID; }
};
Alternative:
class A
{
public:
A(int id = 0) : ID(id) {}
const int ID;
getID() { return ID; }
};
class B : public A
{
public:
B() : A(1) {}
};
It would indeed be very useful to have virtual static members in C++. They could easily be added to the language, no new keywords are necessary. The following code for example names shape types for a graphics library:
class Shape {
public:
static constinit virtual std::string name = delete;
static constexpr virtual bool closed = delete;
...
};
class Circle : public Shape {
public:
static constinit std::string name override { "circle" };
static constexpr bool close override { true };
...
};
class Line : public Shape {
public:
static constinit std::string name override { "line" };
static constexpr bool close override { false };
...
};
This declares Shape as an abstract base class, as the construction of Shape::name and Shape::closed are explicitely skipped via = delete.
The space for virtual static members could be allocated in the same VTable, that is already used for virtual function calls. If all virtual static members are constinit (new with C++20) or constexpr, then the VTable can be written to read-only memory, where most compilers write it currently, too. If not, then the VTable has to be placed in read-write memory instead.
In general, virtual static members don't need to be const, they could also be read-write.
Virtual static members could both be accessed with the classname as a prefix (where they will behave like normal static members) or via an object, where the object's VTable pointer will be used to access the right VTable.
As long, as they are not in the standard, they can be emulated using virtual functions, that return a reference to a local static variable:
virtual const std::string& get_name() const {
static const std::string name { "circle" };
return name;
}
In case, that a derived class does not override the static member (respectively the virtual getter function), the semantics between the real virtual static members and the emulated virtual static members are a bit different: The real virtual static member between parent and child class would actually refer to different instances of that object, with the constructor called for the parent and each child, which doesn't override the virtual static member. But the emulated getter function would always return a reference to exactly the same object. On read-only virtual static members, this shouldn't make a difference (unless the constructor actually initializes each instance differently), but on read-write virtual static members, updating them would make a difference.

Testing for Type Equality without RTTI

Say B and C are derived from A. I want to be able to test whether any two instances of classes derived from A are instances of the same class, that is, whether A* foo and A* bar both point to B instances, without using RTTI. My current solution is something like this:
class A {
protected:
typedef uintptr_t Code;
virtual Code code() const = 0;
}; // class A
class B : public A {
protected:
virtual Code code() const { return Code(&identity); }
private:
static int identity;
}; // class B
class C : public A {
protected:
virtual Code code() const { return Code(&identity); }
private:
static int identity;
}; // class C
Using this method, operator== can simply test first.code() == second.code(). I'd like to remove the literal identity from the derived classes and have the code found automatically by A, so that not all of the derived classes have to repeat this idiom. Again, I would strongly prefer not to use RTTI. Is there any way to do this?
Note: I have seen recent questions [1] and [2], and this is not a duplicate. Those posters want to test the contents of their derived classes; I merely want to test the identities.
You should just use RTTI instead of reinventing the wheel.
If you insist on not using RTTI, you could use CRTP and a function-local static variable to avoid having to write the function to every derived class. Adapt from this example code I wrote for Wikipedia: http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern#Polymorphic_copy_construction
Another alternative is reading the vtable pointer (via this and pointer arithmetics), but that would depend on both the compiler and the platform, so it is not portable.
Your idea is on the right track; maybe you can eliminate some boilerplate with a template:
class TypeTagged {
public:
virtual Code code() const = 0;
}
template <class T>
class TypeTaggedImpl: public virtual TypeTagged {
public:
virtual Code code() const { return Code(&id); }
private:
static int id;
}
Then your client classes just need to be declared like this:
class A: public TypeTaggedImpl<A> { ... }
class B: public A, public TypeTaggedImpl<B> { ... }
The different instantiations of TypeTagged mean that the types have different id fields and hence different IDs; the virtual base type means that the code for the most derived type gets returned.
You can have the Base class to take id as a constructor parameter and implement the identity() function in base class itself. Then there is no need to repeat the code in derived classes. In the derived class constructor, you can do something like derived::derived(): base(0) Sample Code:
class A
{
public:
A(int n) : m_id(n)
{
}
virtual ~A(){}
virtual int id() const
{
return m_id;
}
private:
int m_id;
};
class B : public A
{
public:
B() : A(0)
{
}
};
you can use the both macro __FILE__ __LINE__ as your code
this will avoid the collision problem
you can map this values to an int