Reputation: 7864
Are there any cases where we do down casting of objects?
If we do, why?
I have observed a way of hiding implementation using the below code. Is this the correct way to do? Is there any 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 does not makes sense. I agree. I still have not figured out a proper way of hiding the implementation details from the client.
UncleBens I termed this thing wrongly as Object slicing. Basically, I was referring to this (Object Slicing) as the information related to derived part is missing.
S.Soni Thanks for giving a wonderful explaination. Now, I can really put forward question.
Consider a clients perspective. The only class which are visible to him is class A and the Helper class (because I have hidden implementation behind AImpl
Client has to write the following code as he is unaware of AImpl class
int main(){
A *a = new A();
Helper.doWork(a);
// ...
}
As you said AImpl * in this case will actually be pointing to the base class object, which is wrong (you have explained it with a great example), so this approach of hiding implementation is not correct.
Any attempt to access a derived class member function will result in a crash (and correctly so).
How should I go about hiding the implementation in this case? This is a design problem now?
Upvotes: 2
Views: 1475
Reputation: 42227
You can use PIMPL to hide implementation details, mask dependencies, and speed up builds.
http://www.gotw.ca/gotw/028.htm
http://www.ddj.com/cpp/205918714
http://www.gotw.ca/gotw/024.htm
Upvotes: 0
Reputation: 116674
Your example code contains at least 4 syntax errors, so it's hard to judge what you're trying to do.
And it logically won't work either. You have a class AImpl
that inherits A
, then a member function that takes an A
and appears to try to dynamic-cast it to an AImpl
. But it isn't an AImpl
, because it's just an A
, as that is how the parameter is declared. If you were to pass an instance of AImpl
to that function, it would be sliced down to just an A
.
You could make it a reference or pointer to an A
, and then it could be an AImpl
. Dynamic casts are only ever of use on references or pointers.
Down-casting is used when we have a variable or parameter that has the static type of a base class but we logically know that it is (or might be) of a derived class. It is avoided wherever possible because it means that the compilation process is not able to completely check the type-correctness of the program, i.e. the answer to the question "are you trying to put a square peg into a round hole" cannot be fully answered until runtime.
Update after question was edited
It sounds like you want clients of your library to have access to a limited interface to an object, A, but when they pass it to a function in your library you will have access to the full interface. You could 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 LibraryThing
class can access the private members of A
, because it is declared as a friend of A
.
The downside is that LibraryThing
can access everything in A
, so it means that as the author of the library, you won't be able to benefit from encapsulation. Only users of your library will.
Upvotes: 1
Reputation: 6506
**Are there any cases where we do down casting of objects**
The purpose of dynamic_cast is to perform casts on polymorphic types. For example, given two polymorphic classes Band D, with D derived from B, a dynamic_cast can always cast a D* pointer into a B* pointer. This is because a base pointer can always point to a derived object. But a dynamic_cast can cast a B* pointer into a D* pointer only if the object being pointed to actually is a D object.
**`Is there any better way to achieve the same`**
Perhaps the most important of the new casting operators is dynamic_cast. The dynamic_cast performs a run-time cast that verifies the validity of a cast.
1) Your class is not polymorphic.A class that declares or inherits a virtual function is called a polymorphic class
2) Syntax of dynamic_cast is dynamic__cast (expr)
1st Edit :
Try like 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;
}
};
Study 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;
}
Upvotes: 2
Reputation: 4511
Well, if the following holds true (not the only valid reasons, but a common one):
then using this way is quite common.
However, if it is simply not allowed to use any other implementation (because only your library core may implement the interface), then asserting the type would be nice too; this would provide a nice landing in the debugger or crash-dump for any user of the library who messed with it in a way it should not be done. Of course, the documentation should clearly indicate that deriving from A
is a bad idea.
Upvotes: 1
Reputation: 41331
From your code and the information that the passed in pointer actually points to an A, and not an AImpl, also the constructor AImpl that accepts an A*, I gather that what you want it:
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 cast a base instance into an instance of a derived class (where would the missing derived part come from??).
Upvotes: 1