C++: Determining derived type from a base type pointer - c++

Background:
See this question in the C++ FAQ for a similar situation that I need to solve, but with named constructors.
I have a Base class, class B.
I have a Derived class from B, class D, that adds additional functionality via functions, members, and additional memory allocation.
The additional functionality is polymorphically supported in class B by doing nothing or returning default values and nullptrs from the virtual functions specific to class D.
class B uses public static Factory Methods for construction with all protected constructors. (see: Named Constructor Idiom)
class D uses public static Factory Methods for construction with all protected constructors that are named differently from class B and not available in class B.
Sometime later, a new interface class is created, class A. This class has an interface such that the derived classes from class A must have a getter function and a setter function that both require a pointer to a class B but the dynamic value can be either class B or class D
Question:
I want to derive class A and create a copy constructor, an assignment operator, and/or a setter for class B but because class A only exposes its member(s) as an object of type B I have no way of determining if the object returned is class B or class D.
How would I correctly implement the above using only the public interface without causing slicing or memory issues (including if the above is set up wrong and needs to be changed)?
Possible solutions?:
I'm tempted to try a couple of options:
1) Create a member in class B and all derived types that declares the type of object:
if(getB()->GetType() == "D") {
//Call D::CreateD(...)
} else if(getB()->GetType() == "B") {
//Call B::CreateB(...)
}
2) Dynamically cast to the derived type and check for failure:
if(dynamic_cast<D*>(getB()) == nullptr) {
//Call B::CreateB(...)
} else {
//Call D::CreateD(...)
}
3) Use a virtual method that is specific to class D that I know returns nullptr when used on a class B object:
if(getB()->VirtualMethodSpecificToClassD() == nullptr) {
//Call B::CreateB(...)
} else {
//Call D::CreateD(...)
}
All three cases have code smells:
Causes "else-if-heimers".
Not too sure this will actually work.
Violates the good practice of "code to interfaces not implementations".

As per zneak's comment, I think that if you're using factory methods and private constructors, there's nothing too smelly about having a
virtual B* copy() const { return new B(*this); /* calls private B::B(const B&) */ }
method in class B, overridden in class D (returning a new D* -- this usage of covariant return types is specifically permitted in C++).
Then your A copy constructor can do something like
A::A(const A& other) : b(other.getB()->copy()) {}
and it should work okay.
On the other hand, if you'd rather go with one of the solutions you've suggested, I think that the first is the least pungent -- although I'd go for an enum rather than a string, so you can use a simple switch statement rather than string compares. I believe LLVM uses something like this for "dynamic casting", to avoid the C++ RTTI overhead.

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.

Does "Constructor of an abstract class" exists?

We can not create an object of abstract class. And constructors create new instances of any class which is called as an object.
This is what I know about the constructor, class and object relationship.
Please correct me if I am wrong.
Does it exist?
#include <iostream>
class A
{
public:
virtual void f() = 0;
A()
{
std::cout << "Yes it does!" << std::endl;
}
};
class B: public A
{
public:
void f() {}
};
int main()
{
B b;
return 0;
}
Yes it does!
The technical reason is that somebody needs to initialize the members of A and that's the job of the constructor. But you can easily reason it as follows:
The inheritance relation is often termed with "is". For example, an object of type B is also of type A. In other words B is a kind of A. The constructor of A constructs an object of type A. But b above is also a kind of A, so A must have a constructor to be able to construct it.
Yes! It has to exist, since constructors of any child class make a call to the base constructor. (This is the simplest way to explain it)
Does “Constructor of an abstract class” exists?
Let's say that there can be an abstract class constructor. Just like any other class. By default (if you don't declare a "custom" constructor or you don't have member objects that have no default constructor) there are two implicitly defined: the default constructor and the copy constructor.
So in a declaration like this:
struct abstract_class {
virtual void func() = 0;
}
you still have constructors.
We can not create an object of abstract class.
Yes. For the most common definition of abstract class, that is true. If a class does have pure virtual functions, it is considered to be an abstract class and of course it cannot be instantiated.
And constructors create new instances of any class which is called as an object.
I'd rephrase that to: You construct objects of a class type via their constructor. And yes, in C++, an object is (from §1.8/1):
An object is a region of storage.
And that's that. For example:
int x = 0;
is an object too. An object does not necessarily mean a class type.
Abstract classes can contain member variables and to initialize those member variables Abstract classes need constructor.

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.

C++ allocate objects on heap of base class with protected constructors via inheritance

I have a class with protected constructor:
class B {
protected:
B(){};
};
Now I derive from it and define two static functions and I manage to actually create objects of the class B, but not on the heap:
class A : public B {
public:
static B createOnStack() {return B();}
//static B* createOnHeap() {return new B;} //Compile time Error on VS2010
};
B b = A::createOnStack(); //This works on VS2010!
The question is: 1) Is VS2010 wrong in allowing the first case? 2) Is it possible to create objects of B without modifying B in any way (no friendship and no extra functions).
I am asking, because it is possible to make something similar when dealing with instances of B and its member functions, see:
http://accu.org/index.php/journals/296
Thank you in advance for any suggestion!
Kind regards
Yes, this code is non-compliant. This is related to special rules for protected member access (C++03 draft, 11.5/1):
When a friend or a member function of a derived class references a protected nonstatic member function or
protected nonstatic data member of a base class, an access check applies in addition to those described earlier in clause 11.10). Except when forming a pointer to member (5.3.1), the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class) (5.2.5).
When you use B() or new B(), you're effectively using the constructor through a pointer to the base class.
You can create an object of type A (I assume that A is as posted - no additional members/non-static functions) and use it instead. If you're creating it on stack, everything should work fine, unless you're trying to assign other objects of type B to it. If you're creating it on heap, everything is fine as long as B's destructor is virtual. If B's destructor is not virtual, and you're returning new A() as a B*, then deleting the pointer is technically undefined behavior (5.3.5/3:
In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined.
However you'll probably find it working fine in practice, so you can rely on the actual behavior if there is no other workaround (i.e. use it as a last resort).
There is a common misunderstanding on what protected actually means. It means that the derived class can access that particular member on itself not on other objects. The compiler should have rejected both functions as in both cases it is accessing the constructor of an object that is not of the derived type.
Another example, easier to discuss for its correctness would be:
struct base {
protected:
int x;
};
struct derived : base{
static void modify( base& b ) {
b.x = 5; // error
}
};
The commented line is an error as it is trying to modify an object of type base, not necessarily a derived object. If the language allowed that code to compile, then you would be able to modify an object of type base or even objects of types derived1, derived2... effectively breaking access rules.
struct derived2 : base {};
int main() {
base b;
derived2 d;
derived::modify( b ); // modifying a base!!!
derived::modify( d ); // modifying a derived2!!!
}