Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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:

  1. Causes "else-if-heimers".
  2. Not too sure this will actually work.
  3. Violates the good practice of "code to interfaces not implementations".
like image 259
Casey Avatar asked Oct 21 '22 21:10

Casey


1 Answers

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.

like image 118
Tristan Brindle Avatar answered Nov 15 '22 06:11

Tristan Brindle