Sidecasting to other known superclass - c++

I have a class inheriting from two other (Virtual) classes.
Let's call my two superclasses A and B. I can have objects that only inherit from A, objects that only inherit from B, and objects that inherit from both A and B.
Now, optimally, I'd like to have a container somewhere that holds objects known to inherit from both: Apologies for the C/Java syntax mashup, but this could look something like follows: std::vector<? : A, B>. Now, this doesn't exist, but as it turns out the class holding my container mainly uses the "A" functionality of those classes, which is why I'm currently using std::vector<A*>.
However, at one particular place somewhere else in my code, in a different place, that same vector gets accessed, but with the intention of using the "B" functionality.
While I personally know that I've made sure that all instances added to my vector extend from both A and B, the compiler does not. That makes it obviously difficult for me to access that B functionality.
So therefore, my question is as follows: How do I "sidecast" something from A to B? I have a pointer to A, with the dynamic type of something LIKE C (ie, inhereting from A and B - but not necessarily a SPECIFIC C), but want to get a pointer to B, obviously without changing the dynamic type.
dynamic_cast does the job, but I assume that's an ugly way of doing it. Any better ideas?

The way to do a sidecast is with a dynamic_cast. (You can even put this to the test. Head over to cppreference.com and search for "sidecast". There is exactly one hit.) The dynamic_cast will use its dynamic magic to ensure that the pointed-to object does in fact inherit from the new class (e.g. B) and dynamically determine what offset needs to be added to the pointer to perform the sidecast.
I would not call the dynamic_cast approach "ugly", but I do find it lacking in elegance. Acceptable, but not highly desired. I would prefer a more structured approach, given the assertion that the objects in question are known to inherit from both A and B. (If it weren't for this assertion, dynamic_cast would appear to be potentially the correct approach.)
You have a container somewhere that holds objects known to inherit from both A and B. Is there a name for such objects? If so, that could be the basis for a new class, call it AB, that inherits from A and B. It might do nothing other than inherit from those two classes, but that can still serve a useful role in your container. If your container were to hold pointers to AB, then the container would self-document that all elements must derive from both A and B. In addition, there would be no need to check types dynamically, nor to handle a failure to sidecast. The compiler would enforce that an object has to derive from both A and B to be added to the container in the first place. Furthermore, there would be no need to dynamically calculate an offset, as that offset gets baked into AB. The overall result is cleaner code with more checks made at compile-time. I would prefer this solution.
A comment from the OP makes the assertion that this proposed AB would "basically be completely empty and only serve as a wrapper, which is kind of ugly." I disagree with the "ugly" part, although I do not seek to argue that such an opinion is wrong. I will, though, point out that there is precedent. As far as the public interface goes, std::iostream is basically completely empty and only serves as a wrapper for std::istream combined with std::ostream. Its role is similar to what I propose for AB. You are welcome to consider std::iostream ugly, but it is undeniably standard.

There is no guarantee that the addresses of A and B in your objects will be the same, or even that the difference between these addresses will be the same for all C, D, E, F. This implies that you need to supply additional data for each element of the vector, which will tell how to get a pointer to base classes A and B.
dynamic_cast extracts this additional data from the virtual table (assuming that the compiler implements RTTI via the virtual table).
Pros:
No memory overhead.
Scalable, in case you want to add a third, fourth, etc base classes.
Cons:
Requires RTTI.
dynamic_cast can be somewhat slow (if it's implemented via traversing the class hierarchy).
Possible alternatives:
1. Adapter
class Adapter {
public:
template<class C>
/* implicit */ Adapter(C* pointer):
pointer_a_(pointer),
pointer_b_(pointer) {
static_assert(std::is_base_of_v<A, C> && std::is_base_of_v<B, C>,
"C should be derived from both A and B.");
}
A* getA() const { return pointer_a_; }
B* getB() const { return pointer_b_; }
private:
A* pointer_a_ = nullptr;
B* pointer_b_ = nullptr;
};
int main() {
std::vector<Adapter> my_vector;
C1 c1;
C2 c2;
my_vector.emplace_back(&c1);
my_vector.emplace_back(&c2);
for (Adapter& elem : my_vector) {
elem->getA()->foo();
elem->getB()->bar();
}
}
Pros:
Doesn't require RTTI.
Fast.
Can ensure at compile time that the objects in the vector are actually derived from both A and B.
Cons:
Memory overhead (per object) from the additional pointer.
2. Add a virtual function B* A::getB().
class A {
public:
// Return this (casted to B*), or nullptr if the dynamic object is not derived from B.
virtual B* getB() { return nullptr; }
// ...
};
class C : public FooWhichInheritsB, public A {
public:
B* getB() override { return this; }
};
int main() {
std::vector<A*> my_vector;
C1 c1;
C2 c2;
my_vector.emplace_back(&c1);
my_vector.emplace_back(&c2);
for (A* elem : my_vector) {
elem->foo();
elem->getB()->bar();
}
}
Pros:
Doesn't require RTTI.
No memory overhead (per object).
Calling the virtual function getB() is faster than performing dynamic_cast.
Cons:
Calling the virtual function getB() is slower than simply reading the pointer_b_ member in the Adapter implementation.
You need to remember to override getB() in each C, D, E, F, ...
3. Introduce a common base class AB
class AB : public A, public B {};
class C : public AB { /* ... */ };
class D : public AB { /* ... */ };
Pros:
Doesn't require RTTI.
No memory overhead (per object).
Even faster than Adapter.
Cons:
Adds a constraint on the class hierarchy - you can no longer add an object of the type class Foo : public A2, public B {}; (where A2 is derived from A) to the vector.

Related

Using base assignment operator to rewrite only part of struct [duplicate]

Assuming I have a base class A and publicly derived class B, how should I assign A object to the A base class subobject of B?
class A {...};
class B : public A {...};
A a(..);
B b(..);
static_cast<A&>(b) = a; ???
Is that doable without writing assignement operator for B? Are there any potential problems with casting b to A&? Is that standard conformant?
Writing another answer to demonstrate why and how assign a base class object to a derived class object.
struct TimeMachineThing_Data {
..
..
};
class TimeMachineThing : private TimeMachineThing_Data
{
static std::stack<TimeMachineThing_Data> m_stateHistory;
void SaveState() {
m_stateHistory.push_back( static_cast<TimeMachineThing_Data&>(*this) );
}
void RestoreState() {
static_cast<TimeMachineThing_Data&>(*this) = m_stateHistory.front();
m_stateHistory.pop_front();
}
};
It's very useful and fully legitimate.
(Here is private inheritance, so only internally TimeMachineThing IS-A TimeMachinetime_Data)
Another one.
struct StructWithHundresField {
string title;
string author;
...
StructWithHundresField() {
...
}
};
class EasyResetClass : public StructWithHundresField {
int not_reset_this_attriute;
public:
void ResetToInitialStateAtAnyTime() {
static_cast<StructWithHundresField&>(*this) = StructWithHundresField();
}
}
That's a really bad idea. A is the base, B is a derived type. By casting B to an A, you are now using A's assignment operator, which isn't going to touch any of the extra derived data. At the end of that assignment, b is still considered to be of type B, even though it now contains an A. This is the opposite of the way inheritance is meant to be used.
Changing the line to b = reinterpret_cast<B&>(a); would be even worse. Then you would be pretending that a is a B when it's not, and you be reading invalid memory.
If you truly want to do this kind of assignment, you want:
class B : public A {
B& operator= (const A& a) { ... }
};
Then you can write a function to copy the information from the A, and somehow deal with the extra information in the derived type B, plus this would allow you to simply write:
b = a;
In C++ (as with other OOP languages) inheritance establish Is-A relationship.
That is, if B publicly inherit A, B = A.
You always can cast B instance to A reference without any worry.
Think for a minute about whether this is a good idea. Remember that if you have B subclassing A, then every B is an A but not every A is a B. For example, every dog is a mammal, but not every mammal is a dog. If you have a concrete B object, trying to set it to an A object isn't mathematically well-defined in most cases. Moreover, in the world of C++, because you B object is statically typed as a B, you can never assign it an object of type A in a way that will make it stop being a B. At best, you're going to overwrite just the A portion of the B object without changing any of the B-specific parts.
Slicing assignment is safe only, if your base class is in
standard layout: https://en.cppreference.com/w/cpp/types/is_standard_layout . Better even, if your derived class is also standard layout.
In particular, your base class must not contain virtual methods or a virtual destructor, and all non-static data members must have the same access control (like public or private). Your base class may have a base class itself, and it may have data members, that are objects of other classes, but all those classes, that you that way inherit into your base class, must also be standard layout.
If your base class is standard layout, then there is nothing wrong with a slicing assignment to it, as that is guaranteed to only touch the data members of the base class. All other cases are unsafe, though.
I would say you need an assignment operator that specifically copies an A object to a B object.
In general, it's a good idea to have one any way when copying objects of the same type. But objects of different types make it even more important.
static_cast<TimeMachineThing_Data&>(*this) = m_stateHistory.front(); can be rewritten without the cast as TimeMachineThing_Data & data = *this; data = m_stateHistory.front();.
Everyone should know assignment is a covariant binary operator and therefore cannot work correctly with virtual functions. This is true for most binary operators, but assignment is special because it is part of the C++ language.
If you are using OO, your objects should be uncopyable and always represented by pointers. Uniqueness of object identity is the heart of OO: objects are not values, they have a unique value (their address).
If you are playing with values you should be using the appropriate concepts: functional programming (FP). That's closures (applicative objects), switches, templates, variants, and other stuff.
Try to get a solid understanding of each before mixing them. In general FP subsumes OO so is the general methodology: OO is a special case that in special circumstances delivers safe dynamic dispatch. OO dispatch is linear which means it handles an unbounded set of subtypes but it also applies only to properties (functions with one variant argument, namely the object) and can't work for anything higher order (functions with more than one variant argument). Assignment is just another 2-ary function, hence, it can't be dispatched with virtual functions.

Should functions return pointer to derived or base class?

When a function needs to return an object. Should it return it through a pointer to derived or base?
class B{
}
class D:public B{
}
// way 1: return pointer to derived
D* createDerived(){
D* d = new D();
return d;
}
// way 2: return pointer to base
B* createDerived(){
B* d = new D();
return d;
}
I have heard of "program to an interface not an implementation" which would suggest that we should return a pointer to base. However my intuition says it is better in this case to return a pointer to derived, because if the client code uses base pointers, this function would still work! On the other hand, if we return pointer to base and the client code uses derived pointers, this would not work for them. It seems that by returning a more "specific" pointer, we are allowing more flexibility for client code.
Another way to look at it is from the perspective of "program by contract." One of the suggestions is to promise as little as you can. By promising that we will return a very specific object, we follow this rule. However if we return a base pointer, it seems to me that we are promising a lot more.
Which is better design? Is my reasoning above correct?
I have a lot to learn on how to make modular, maintainable, extensible software, so please excuse if my reasoning/conclusion is nooby. I am very interested in learning. Thank you so much for your time.
It isn't possible to answer this question in a general way. In particular, returning the more derived object imposes additional restrictions on future implementations of the method, while returning the base class imposes more restrictions on the caller. Which is best depends on the design of the application or library, and in particular the scope of functionality offered by B and D and the overall design of the API.
In general, you want to return the most-derived, or, loosely speaking, the most functional class, which doesn't constrain your future implementation choices. This allows your clients to use the return value efficiently, while still allowing you to the change the implementation in the future.
The primary downside of using the derived class D is that you expose more details to the client, which may be difficult or impossible to reverse later.
For example, imagine that that you have a method reverse(std::ReversibleContainer &cont), which takes a container and returns a reversed snapshot of it (i.e., changes to the underlying container don't effect the returned snapshot).
In your initial implementation, you might decide to implement this as:
template<class BidirectionalIterator>
std::list<T> reverse(BidirectionalIterator &start, BidirectionalIterator &end) {
std::vector output;
std::copy(input.begin(), input.end(), back_inserter(output))
return output;
}
Later on, you might realize that you can avoid the copy of the underlying data for certain cases where the container (and elements) are constant, for example:
ImmutableIterator reverse(ImmutableBiderectionalIterator &input) {
return ReversingImmutableBiderectionalIterator(input);
}
This container can use the knowledge that the input container is read-only to return a view of the input container, avoiding the copy, which simply remaps each access to result in the same semantics as a reversed container.
I suggest you to rename member functions to createB and createD and in second case return pointer to derived class, because you always can cast derived class pointer to base class, when reverse cast may fail.
The correct answer imo is neither. There is usually no need to return raw pointers from functions in your own code (exceptions below).
Instead, just return the created object itself:
class B { virtual ~B(){} };
class D : public B {};
// this function would make real sense only if D were a class template
auto createD()
{
return D{};
}
This suffices in about any cases. Moreover, and importantly, it expresses what you get, namely an object of type D which you can use as required. Instead, when you get a raw pointer, it's from the first (i.e. without guessing the behaviour from the function name, reading the documentation, etc.) unclear what you're allowed to do with this raw pointer. Can you wrap it inside a unique_ptr? Are you allowed to delete it? Unclear. Returning an object (or better, a well-designed object, which basically means consistent RAII) releases you from having to answer those question -- just do what you want with the object.
Further, if you really need the pointer (which is an abstraction from the object), you can still wrap the return inside a suitable smart pointer like
auto d_uptr = std::make_unique<D>(createDerived());
auto d_sptr = std::make_shared<D>(createDerived());
or, similarly, also into smart base class pointers,
std::unique_ptr<B> = std::make_unique<D>(createDerived());
std::shared_ptr<B> b_sptr = std::make_shared<D>(createDerived());
This uses copy elision to construct the pointees and produces no overhead as compared to your function returning a D*. Note that as a rule the pointer should be a smart pointer, because only then you are freed directly from the obligation of having to delete it correctly somewhere later in the code.
One exception where you need raw pointers as function return types is the clone pattern, which applies when you want to copy an object via a base class pointer. Here one should use smart pointers as well as the function invoked by the user, but inside the class one has to use raw pointers in order to allow for covariant return types of virtual functions:
class B
{
virtual ~B(){}
auto clone() const
{
return std::unique_ptr<B>(clone_impl());
}
protected:
virtual B* clone_impl() const = 0;
};
class D : public B
{
protected:
virtual D* clone_impl() const { return new D{*this}; };
};
There might be a lot of other exceptions (e.g. always when covariance is used) which I don't have in mind at the moment. But those are not that important imo.
Summarizing: don't use raw pointers as function return types unless you have a good reason to do so.

C++ - Reach derived class variables from vector

I'm really confused, so I have to ask this. I try to write an application, but I don't know how to reach the variables of the derived class, which are in a vector in the Base class.
The code is:
class A {
public:
A() { };
std::vector<A> aVector;
void Foo();
}
class B : public A {
public:
B() { };
int j;
}
void A::Foo() {
aVector.push_back( B() );
// Here I would like to reach B::j, but only the members and variables of A comes in
aVector[0].j; // wrong
B b = aVector[0]; // no suitable user-defined conversion from "A" to "B" exists
// should I use cast? which one?
}
I'm currently learning inheritance and this kind of things through application programming, and now I'm really stuck.
I looked for other questions, but could not find any that solves my problem. If there is, and I missed, then sorry.
You need to store pointers to A so that your new B object won't get "sliced" (see explanation here) when pushed into the vector.
Also, when you want to use specifically a child method / variable on a pointer from the base class, you need to cast it into the proper type
std::vector<A*> aVector;
aVector.push_back(new B());
B* b = (B*)aVector[0];
cout << b->j;
// remember to delete the content of aVector
Casting an object like this can be dangerous if you are not 100% sure that it is of the type you're casting it in.
See this thread for more information on casting (C style, dynamic_cast and static_cast)
Since the vector is declared to hold objects of type A, when you push a B in to the vector, all the B-ness is stripped away from the object that's stored in the vector. This is known as the slicing problem.
When you later try to access the B elements of the objects stored in the vector you can't because they simply don't exist. You don't have a vector of B objects -- you have a vector of A objects.
In order to solve this problem, you need to store A objects not by value, but by reference or by pointer. You can't store references in a vector, so this leaves you with pointers.
This has nothing to with vectors. If B derives from A then the following code:
A a;
B b = a;
is an error (unless there is some method to convert).
This is correct - your vector items you should be able to handle uniformly. If this means the code that uses the vector expects all items to be B then just make a vector<B>. If not, then you have no business converting an A to a B anyway.
You should never try to access derived class members from the base class. The base class should be agnostic about the implementation details of the derived class. What you are doing is not polymorphic. In other words your B instances cannot act like A instances, because you provided no virtual methods and overrode no virtual methods.
The entire design and approach is incorrect. A::Foo() should be a virtual method (Perhaps even abstract). And you should be doing the work in B::Foo().
And another thing, you shouldn't hold a vector of just plain old A. It should be pointers to A. So std::Vector. And that member should be prefixed with the letter m, to indicate it's a member variable of the class. So std::vector mSomething;

C++ Inheritance. Changing Object data Types

I am having trouble with forcing data type changes has on my own objects. I have a base class say A and two classes derived from A called B and C. I pass objects B and C to a function that checks which type of object it is (B or C). Here is some example code below and the question to my problem:
enum ClassType {"B", "C"};
class A {
protected:
m_Type;
public:
ClassType Type() { return m_Type}
...
...
};
class B : public A {
otherMemberFunctions();
}
class C : public A {
otherMemberFunctions();
}
void WhatType(vector<A*>* candidates){
vector<B*> b_candidates(0);
vector<C*> c_candidates(0);
for(int i = 0; i < candidates->size(); i++){
if(candidates->at(i)->Type() == B ){
B* b = (B*) candidates->at(i);
b_candidates(b);
}
//Same idea for Object C
}
}
I would then use WhatType(vector<A*>* candidates) as follows
vector<B*>* b_example
WhatType((vector<A*>*) b_exmaple)
When I have filled the new vector b_candidates in the function WhatType. Will I still have access to the member functions in the B object or will I only have the access to the member functions in the base class A?
I am confused to what happens with the object when I change the type of the object.
Here
WhatType((vector<A*>*) b_exmaple)
and here
B* b = (B*) candidates->at(i);
When you receive a pointer to a polymorphic object you have two types: the "static" type of the object, which, in your case, will be A *, and its "dynamic" or "real" type, that depends on what was actually assigned to it.
Casting your A * to B * forces the compiler to consider that pointer as a pointer to B; this is safe as long as you actually know that that pointer is actually a pointer to B, otherwise the compiler will start writing nonsensical code (invoking B methods on data of another type).
The checks you are trying to implement are a homegrown version of RTTI, which is a mechanism that allows you to know which is the "real type" of a pointer or a reference to a polymorphic class, and to perform that kind of casts safely. Check out typeid and dynamic_cast on your C++ manual for more info about it. (Incidentally, IIRC dynamic_cast is not only for safety in case the dynamic type is wrong, but it may perform also some extra magic on your pointer if you use it in complicated class hierarchies; so, avoid C-style casting for polymorphic classes)
By the way, in general it's considered "code smell" to have to manually check the "real type" of the pointer in order to cast it and use its methods: the OOP ideal would be being able to do the work only though virtual methods available in the base class.
Big warning: RTTI works only on polymorphic classes, i.e. classes that have at least one virtual method. On the other hand, if you are building a class hierarchy where objects are being passed around as pointers to the base class you'll almost surely want to have a virtual destructor, so that's no big deal.
Since you cast to B*, you will have access to B's members.
The actual type of the objects does not change, of course, but if you only have a pointer (or reference) to the base class you can not access fields specific to the sub-classes.
What you can do to access sub-class fields is to use dynamic_cast to cast it to the sub-class:
A *a = new B; // We cant reach the members of class B in a
B *b = dynamic_cast<B *>(a); // But now we have a proper pointer to B
Ok, so if you had an object of type B instantiated on the heap and held by a pointer of type A. you can only see type A's member functions, to access type B's member functions you have to static_cast<B*> which is what the ... "(B*)" ... is doing.
dynamic cast is better as it will return a null if the conversion is not possible. but of course it happens a run-time so there's a penalty.
As B and C are À derived, a vector<B *> and vector<C *> contains A base class objects. If you ensure to set your A::m_Type attribute in your constructor, you will no have problems:
enum ClassType {'B', 'C'}; // see I modified your definition
class A {
protected:
ClassType m_Type;
public:
ClassType Type() { return m_Type};
...
...
};
class B : public A {
public:
B() : m_Type('B') {}
....
};
Using this, you will check without problems your B and Cobjects. After that, as you are casting base objects to derived ones, you will have fully access to their public methods and attributes.

how to assign base class object to a derived class object?

Assuming I have a base class A and publicly derived class B, how should I assign A object to the A base class subobject of B?
class A {...};
class B : public A {...};
A a(..);
B b(..);
static_cast<A&>(b) = a; ???
Is that doable without writing assignement operator for B? Are there any potential problems with casting b to A&? Is that standard conformant?
Writing another answer to demonstrate why and how assign a base class object to a derived class object.
struct TimeMachineThing_Data {
..
..
};
class TimeMachineThing : private TimeMachineThing_Data
{
static std::stack<TimeMachineThing_Data> m_stateHistory;
void SaveState() {
m_stateHistory.push_back( static_cast<TimeMachineThing_Data&>(*this) );
}
void RestoreState() {
static_cast<TimeMachineThing_Data&>(*this) = m_stateHistory.front();
m_stateHistory.pop_front();
}
};
It's very useful and fully legitimate.
(Here is private inheritance, so only internally TimeMachineThing IS-A TimeMachinetime_Data)
Another one.
struct StructWithHundresField {
string title;
string author;
...
StructWithHundresField() {
...
}
};
class EasyResetClass : public StructWithHundresField {
int not_reset_this_attriute;
public:
void ResetToInitialStateAtAnyTime() {
static_cast<StructWithHundresField&>(*this) = StructWithHundresField();
}
}
That's a really bad idea. A is the base, B is a derived type. By casting B to an A, you are now using A's assignment operator, which isn't going to touch any of the extra derived data. At the end of that assignment, b is still considered to be of type B, even though it now contains an A. This is the opposite of the way inheritance is meant to be used.
Changing the line to b = reinterpret_cast<B&>(a); would be even worse. Then you would be pretending that a is a B when it's not, and you be reading invalid memory.
If you truly want to do this kind of assignment, you want:
class B : public A {
B& operator= (const A& a) { ... }
};
Then you can write a function to copy the information from the A, and somehow deal with the extra information in the derived type B, plus this would allow you to simply write:
b = a;
In C++ (as with other OOP languages) inheritance establish Is-A relationship.
That is, if B publicly inherit A, B = A.
You always can cast B instance to A reference without any worry.
Think for a minute about whether this is a good idea. Remember that if you have B subclassing A, then every B is an A but not every A is a B. For example, every dog is a mammal, but not every mammal is a dog. If you have a concrete B object, trying to set it to an A object isn't mathematically well-defined in most cases. Moreover, in the world of C++, because you B object is statically typed as a B, you can never assign it an object of type A in a way that will make it stop being a B. At best, you're going to overwrite just the A portion of the B object without changing any of the B-specific parts.
Slicing assignment is safe only, if your base class is in
standard layout: https://en.cppreference.com/w/cpp/types/is_standard_layout . Better even, if your derived class is also standard layout.
In particular, your base class must not contain virtual methods or a virtual destructor, and all non-static data members must have the same access control (like public or private). Your base class may have a base class itself, and it may have data members, that are objects of other classes, but all those classes, that you that way inherit into your base class, must also be standard layout.
If your base class is standard layout, then there is nothing wrong with a slicing assignment to it, as that is guaranteed to only touch the data members of the base class. All other cases are unsafe, though.
I would say you need an assignment operator that specifically copies an A object to a B object.
In general, it's a good idea to have one any way when copying objects of the same type. But objects of different types make it even more important.
static_cast<TimeMachineThing_Data&>(*this) = m_stateHistory.front(); can be rewritten without the cast as TimeMachineThing_Data & data = *this; data = m_stateHistory.front();.
Everyone should know assignment is a covariant binary operator and therefore cannot work correctly with virtual functions. This is true for most binary operators, but assignment is special because it is part of the C++ language.
If you are using OO, your objects should be uncopyable and always represented by pointers. Uniqueness of object identity is the heart of OO: objects are not values, they have a unique value (their address).
If you are playing with values you should be using the appropriate concepts: functional programming (FP). That's closures (applicative objects), switches, templates, variants, and other stuff.
Try to get a solid understanding of each before mixing them. In general FP subsumes OO so is the general methodology: OO is a special case that in special circumstances delivers safe dynamic dispatch. OO dispatch is linear which means it handles an unbounded set of subtypes but it also applies only to properties (functions with one variant argument, namely the object) and can't work for anything higher order (functions with more than one variant argument). Assignment is just another 2-ary function, hence, it can't be dispatched with virtual functions.