question  Virtual destructor in derived classes

vvadan (23)   Link to this post
please answer the follow question with explanation

Class Base {
Public:
Base();
Virtual ~Base();
};

Class Derived : protected Base {
Public:
Virtual ~Derived();
};

Int main()
{
Base *pb = new Derived;
Return 0;
}


Referring to the sample code above, which one of the following statements is true?
Choice 1 The pointer returned by new cannot be type cast from Derived* to Base*.
Choice 2 The code compiles with no errors.
Choice 3 A constructor needs to be added to Derived class.
Choice 4 A pointer to a Base class cannot point to an instance of a Derived class.
Choice 5 Derived class cannot have a virtual destructor.
jacksome (1)   Link to this post
to vvadan:
I think the choice 2 is true.(but the constructor of the base class has no definition...this is very strange.you can not declaration at all, if you declare the member function, you must make the definition of the function. )

choice 1 : the derived class inherit the Base class, in c++ world, the pointer of the base class can point to the derived class.
choice 3: because the derived class has no more data member than the base class. the derived class can invoke the base class 's the constructor to creat the derived object.
choice 4: because the derived class and the base class are "is-a" ,so the pointer of the base class can point to the instance of a derived class.
choice 5: the derived class also can have the virtual destructor.

that,you can write a small program to test this statements. I believe you can do this easily.
Last edited on
ropez (312)   Link to this post
It's class, public, virtual, return not Class, Public, Virtual, Return.

Why don't you run it through the compiler yourself, instead of guessing what happens?
DrDogg (26)   Link to this post
Firstly, as ropex points out, your keywords need to lose the caps.

Choice 1 can be true or false depending on where the conversion takes place.
Choice 2 is false because of ropex's point and because your member functions have no definitions, only declarations. That is, they have no function bodies. Quick fix: replace ; with {}
Choice 3 is false. The implicitly generated default constructor will do fine.
Choice 4 is false for the same reason that choice 1 is.
Choice 5 is false. As Base's destructor is virtual, Derived's destructor is automatically virtual. The additional virtual keyword on Derived's destructor is legal but redundant.

Consider the following:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
struct A
{
   virtual ~A() {}
};

struct B : protected A
{
   A* f()
   {
      // Legal because the conversion takes place within a
      // member of class derived from A
      return new B; 
   }
};

int main()
{
   B b;
   // Legal because, although it returns a B*, the return type is A*
   A* a = b.f();

   // Error: main is neither a friend of or derived from A
   B* b2 = static_cast<B*>(a);

   // Legal because reinterpret cast doesn't consider inheritance
   // hierachies and access control when converting but NOT SAFE
   // for the same reason.
   B* b3 = reinterpret_cast<B*>(a);
}
Last edited on
satm2008 (151)   Link to this post
DrDogg:

I would not recommend a static_cast<> for a parent-child hierarchy as static cast does not check whether the derived is of same family or not unlike dynamic_cast. For this program dynamic_cast<> is suitable and recommended. Better not think about static_cast in first place.


vvadan:

Let me point it out first, that

a PROTECTED inheritance says that the derived class CAN access the base class's methods and data (if the data scope is, again, protected from the base class), and the same can NOT be accessed by the derived's "object"
meaning, per your code, the

Base *pb = new derived; // definitely a compiler error

as the pointer pb can NOT access the members of base class via derived.

Hence the first one is true, meaning, the line returns error and it can not be downcasted.

All others are false, provided the constructor and destructors are coded right.

I see your code does not have any constructor or destructor code for the declared constructor and destructor methods. Considering the code is provided the constructor and destructors, only the first one is true and all others are false.

Check it out. Good luck :)

DrDogg (26)   Link to this post
satm2008:
In the general case I would agree with you.

However, in this case the intention was for the conversion to fail at compile time, thus we require static_cast. The dynamic_cast will compile but then fail at run time.

I would suggest that the rule of thumb "Better not think about static_cast in first place." be replaced with "Be suspicious of designs requiring casting at all!"

Obviously the casts here are to demonstrate the access rules.
Last edited on
ropez (312)   Link to this post
>> Firstly, as ropex points out...

It's ropez ;-)
DrDogg (26)   Link to this post
Sorry. Typo. My bad!
satm2008 (151)   Link to this post
DrDogg:
>>However, in this case the intention was for the conversion to fail at compile time, thus we require static_cast.

You are missing the point. The prime objective of the questionaire was to test the student's knowledge and skill to analyze.
Hence no question of modifying the code and check it if fails.
Answer the question true or false, based on the given info, agree?

And I agree with your point that, be cautious in using the casting in C/C++
unless you know what you are doing :)

Good luck :)
DrDogg (26)   Link to this post
Consider my code a response to questions one and four. My textual response adequately addresses the other questions. (i.e. clearly the code does not compile etc.)

My code is not intended to be a modification of vvadan's. I wrote it as a new test harness to demonstrate that whilst straight answers to questions one and four may be possible in the specific case, (i.e. the new in main) it is not possible to simply say "Base* to Derived* conversions are/aren't legal" or (vice versa) in the general case. Clearly the set of allowable conversions depends on context and the code provided by vvadan demonstrates only one context. Admittedly the conversion rules I demonstrated also works if private inheritance is used so it does not distinguish between the two.

My apologies if this was not clear in my original post, however, I still maintain that my point is valid and relevant. :-)
Last edited on
rpgfan3233 (111)   Link to this post
Simply put, none of them are true.

Choice 1 - This is false because that is one case where dynamic_cast is meant to be used.
Choice 2 - This is false because the issue with capitalization prevents it from being compiled without errors.
Choice 3 - This is false because it will use the default constructor since main() doesn't construct an instance of Derived with an argument.
Choice 4 - This is false because of polymorphism. An instance of the Derived class is also an instance of the Base class.
Choice 5 - This is false because you CAN make the destructor of a derived class virtual. If it was written "pure virtual" rather than simply "virtual", that would make the statement true.
DrDogg (26)   Link to this post
Aaaaaaaaaarg, nooooo!!! (*DrDogg smacks own head against pointy things*)

>>This is false because that is one case where dynamic_cast is meant to be used.
dynamic_cast will not help at all. dynamic_cast respects access rules. The only ways to make...
 
Base* bp = new Derived;

...work without performing major changes to the code structure are
1
2
3
4
5
6
7
// Define private and protected to be public. Yes, this works, but no, don't do it!
#define private public
#define protected public

// Reinterpret cast doesn't care about many language rules really.
// This may work on your compiler, but again, don't do it. Its brittle and not portable.
Base* bp = reinterpret_cast<Base*>(new Derived);


>> This is false because it will use the default constructor since main() doesn't construct an instance of Derived with an argument.
Yes, the code calls the default constructor, but this would be true whether one was defined explicitly or not. The key point is that Derived doesn't need a USER DEFINED default constructor because the compiler automatically defines one that works just fine.

Note the difference between a default constructor (a constructor taking no arguments) and an implicitly defined constructor. (one provided by the compiler in the absence of a user defined one)

>>This is false because of polymorphism. An instance of the Derived class is also an instance of the Base class.
This is not polymorphism at work, (one class behaving as another) this is access rules at work. (more to do with encapsulation) Yes, I know there is an inheritance hierachy here, but polymorphism is still a red herring. The conversion from Derived* to Base* is forbidden because of the access specifier applied to the base class.

>>This is false because you CAN make the destructor of a derived class virtual. If it was written "pure virtual" rather than simply "virtual", that would make the statement true.
Ok, we can agree on the first sentence. I would add to that, if the base class' destructor is virtual then the derived class' destructor is virtual and there's nothing you can do about it. However, pure virtual destructors are not the problem here.

The issues with this code (apart from syntax) ALL stem from misuse of access control rules.

If Derived defined a pure virtual destructor then it would be an abstract class and thus "new Derived", and thus the example, would be illegal but one could still derive from and use Derived as long as Derived provides a definition for its destructor. If Base had a pure virtual destructor, similarly, as long as it also provides a definition...
1
2
3
4
5
6
struct Base
{
   virtual ~Base() = 0;
};

Base::~Base() {}

... then the code will be fine.
Last edited on
DrDogg (26)   Link to this post
This topic has become rather confusing. I think the problem stems from the initial code having problems that cover many different issues.

We've got issues to do with access control, the use and behaviour of virtual functions, the meaning of different kinds of inheritance, and compiler generated functions.

There are interesting discussions on all these issues in a variety of books, but, would there be general interest in starting some new threads, with some code to discuss, about these issues separately?
rpgfan3233 (111)   Link to this post
> would there be general interest in starting some new threads,
> with some code to discuss, about these issues separately?

I wouldn't object to anything like that! In fact, maybe it might even work out to be in a couple of articles... Those are always useful. ^_^
satm2008 (151)   Link to this post
DrDogg,

I dont think it is a good idea to suggest something which is not suitable and recommended. Saying yourself it is not recommended again stating here simply confuses the original poster and the people who read these posts would ignore your posts thereafter.

static_cast is not at all recommended for an object of class hierarchy as it does not consider any class or polymorphism rules, hence dynamic_cast is recommended in place.

reinterprete_cast is dangerous and meaningless when it comes to class hierarchy.

And you are suggesting to redefine the tokens protected and private to public. When we code in C++ we should abide the language "rules" otherwise we would better write a simple pseudo code and forget about a computer program lol :)

I agree with rpgfan3233 to open a new thread on the same topic and keep the original poster out of this confusion ;)




This topic is archived - New replies not allowed.