Why and where do we use downcasting?

Are there times when we are casting objects?

If we do, why?

I noticed a way to hide the implementation using the code below. Is this the correct way? Is there a better way to achieve the same.

class A{
    public:
      A();
      virtual ~A();
      //exposed virtual functions
};

class AImpl : public A{
    public:
       AImpl(A *obj);
       virtual ~AImpl();     
      //exposed virtual functions++
};

class Helper{ //utility class so i am making constructor and assignment operator as private
    public:
       static bool doWork(A *obj){
          AImpl *objImpl = dynamic_cast<AImpl *> (obj);
          return doWork(objImpl); // some internal function
       }

    private:
         Helper();
         Helper(const Helper& obj);
         const Helper& operator=(const Helper& obj);
};

      

The question still doesn't make sense. I agree. I still haven't figured out the correct way to hide the implementation details from the client.

UncleBens I misnamed this thing as object clipping. Basically, I meant this (Object Slicing) as there is no information related to the derived part.

S.Soni Thanks for the great explanation. Now I can ask a question.

Consider a customer perspective. The only class he can see is class A and class Helper (because I have a hidden implementation behind AImpl

Client should write the following code as he doesn't know AImpl class

int main(){
    A *a = new A();
    Helper.doWork(a);
    // ...
}

      

As you said, AImpl * in this case will actually point to the base class object, which is not correct (you explained this with a great example), so this implementation hiding approach is wrong.

Any attempt to access a member function of a derived class will fail (and rightly so).

How should I hide the implementation in this case? Is this a design problem now?

+2


source to share


5 answers


**Are there any cases where we do down casting of objects**

      

The purpose of dynamic_cast is to render to polymorphic types. For example, given two polymorphic classes: group D, with D derived from B, a dynamic_cast can always point a D * pointer to a B * pointer. This is because the base pointer can always point to a derived object. But dynamic_cast can use a B * pointer into a D * pointer only if the object it points to is actually a D object.

**`Is there any better way to achieve the same`**

      

Perhaps the most important of the new casting operators is dynamic_cast. dynamic_cast performs a runtime cast that validates the cast.

1) Your class is not polymorphic. A class that declares or inherits a virtual function is called a polymorphic class

2) Syntax dynamic_cast dynamic__cast (expr)



1st Edit:

Try this it will work

class A
{
    public:
      A();
      virtual ~A();// Notice here i have put virtual
};

class AImpl : public A
{
    public:
       AImpl(A *obj);
       ~AImpl();     
};

class Helper
{
    public:
        Helper(){}
       static bool doWork(A *obj)
       {
          AImpl *objImpl = dynamic_cast<AImpl*> (obj);
          return true;
       }
};

      

Check out this example:

class Base
{
public:
    virtual void f() { cout << "Inside Base\n"; }
    // ...
};
class Derived: public Base 
{
public:
    void f() { cout << "Inside Derived\n"; }
};


int main()
{  
    Base *bp, b_ob;
    Derived *dp, d_ob;
    dp = dynamic_cast<Derived *> (&d_ob);
    if(dp) {
        cout << "Cast from Derived * to Derived * OK.\n";
        dp->f();
    } else

        cout << "Error\n";
    cout << endl;
    bp = dynamic_cast<Base *> (&d_ob);
    if(bp) {
        cout << "Cast from Derived * to Base * OK.\n";
        bp->f();
    } else
        cout << "Error\n";
    cout << endl;
    bp = dynamic_cast<Base *> (&b_ob);
    if(bp) {
        cout << "Cast from Base * to Base * OK.\n";
        bp->f();
    } else
        cout << "Error\n";
    cout << endl;
    dp = dynamic_cast<Derived *> (&b_ob);
    if(dp)
        cout << "Error\n";
    else
        cout << "Cast from Base * to Derived * not OK.\n";
    cout << endl;
    bp = &d_ob; // bp points to Derived object
    dp = dynamic_cast<Derived *> (bp);
    if(dp) {
        cout << "Casting bp to a Derived * OK\n" <<
            "because bp is really pointing\n" <<
            "to a Derived object.\n";
        dp->f();
    } else
        cout << "Error\n";
    cout << endl;
    bp = &b_ob; // bp points to Base object
    dp = dynamic_cast<Derived *> (bp);
    if(dp)
        cout << "Error";
    else {
        cout << "Now casting bp to a Derived *\n" <<
            "is not OK because bp is really \n" <<
            "pointing to a Base object.\n";
    }
    cout << endl;
    dp = &d_ob; // dp points to Derived object
    bp = dynamic_cast<Base *> (dp);
    if(bp) {
        cout << "Casting dp to a Base * is OK.\n";
        bp->f();
    } else
        cout << "Error\n";
    return 0;
}

      

+2


source


Your sample code contains at least 4 syntax errors, so it is difficult to judge what you are trying to do.

And it doesn't logically work. You have a class AImpl

that inherits A

and then a member function that takes in A

and seems to be trying to dynamically convert it to AImpl

. But it is not AImpl

, because it is simple A

, since this is how the parameter is declared. If you need to pass an instance AImpl

to this function, it will be sliced ​​to A

.

You can make a link or pointer to A

and then it can be AImpl

. Dynamic throws are only used for links or pointers.

Listing down is used when we have a variable or parameter that is of the static type of the base class, but we logically know that it is (or could be) a derived class. It is avoided when possible, because it means that the compilation process is unable to fully verify the correctness of the program type, i.e. The answer to the question "are you trying to fit a square snap into a round hole" cannot be fully answered until runtime.

Update after question has been edited



It sounds like you want your library clients to have access to the restricted interface on object A, but when they pass its functions to your library, you will have access to the full interface. You can just use friend

for this.

class A
{
    friend class LibraryThing;

    void visibleToLibraryThing();

public:
    // ctor, etc.

    void visibleToAll();
};

class LibraryThing
{
public:
    void foo(A &a)
    {
        a.visibleToLibraryThing();
    }
};

      

The class LibraryThing

can access private members A

because it is declared by a friend A

.

The downside is that it LibraryThing

can access everything in A

, so this means that as the author of the library you won't be able to take advantage of encapsulation. Only users of your library will.

+1


source


From your code and the information passed in the pointer actually points to A and not AImpl, also the AImpl constructor that accepts A *, I am assembling what you want:

class Helper{
    public:
       static bool doWork(A *obj){
          AImpl objImpl(obj); //construct an AImpl instance, using available constructor
          return doWork(&objImpl); // some internal function
       }
};

      

There is no way to distinguish between a base instance and a derived class instance (where will the derived part be missing from?).

+1


source


It's good if the following holds true (not the only valid reasons, but general ones):

  • you have an architecture with MVC
  • you want to hide implementation details from client code (no-na ...)
  • you need to pass some references from the kernel to the client code (all kinds of descriptors, etc.).
  • the only valid implementation of public interfaces should be in the core of the MVC part

then the use of this method is quite common.

However, if it is simply not permitted to use some other implementation (because only the core of the library can implement the interface), then a type assertion would be good; this will provide a nice landing in the debugger or crash dump for any user of the library who messed it up in a way that shouldn't be done. Of course, the documentation should clearly state that the conclusion from A

is a bad idea.

+1


source


You can use PIMPL to hide implementation details, mask dependencies, and speed up assembly.

http://www.gotw.ca/gotw/028.htm

http://www.ddj.com/cpp/205918714

http://www.gotw.ca/gotw/024.htm

0


source







All Articles