some C++-specific interview questions

D

Digital Puer

I'm not the world's greatest C++ programmer, so I had a hard
time with these. Some help would be appreciated.

1. Comment on the declaration of function Bar() below:
class Foo
{
static int Bar(int i) const;
}

(I said that since Bar is a static method, it can only access
static variables, not member variables, so the const is
irrelevant.)


2. If you have virtual functions in your class, do you need a virtual
destructor? Why?

(My gut answer was that no, you don't NEED a virtual destructor
unless the derived class is handling its own dynamically-managed
data.)

3. Comment on the following function. What would you change? State
your assumptions:

string & Foo()
{
string default_string = "default answer";
for (vector<node>::iterator iter = mynodes.begin();
iter != mynodes.end();
iter++)
{
cout << iter;
}
return default_string;
}


4. When would you use private inheritence? (I have never personally
used this.)

5. Where in memory is the virtual function lookup table stored?
(I found this one to be way too detailed for me.)

6. Consider member initialisation lists. Why are they needed? Why are
they considered more efficient than initialising members in the body of
the constructor?
 
P

Phlip

Digital said:
I'm not the world's greatest C++ programmer, so I had a hard
time with these. Some help would be appreciated.

The next problem is your interviewer might not be the world's greatest,
either... ;-)
1. Comment on the declaration of function Bar() below:
class Foo
{
static int Bar(int i) const;
}

(I said that since Bar is a static method, it can only access
static variables, not member variables, so the const is
irrelevant.)

I suspect it should not even compile.
2. If you have virtual functions in your class, do you need a virtual
destructor? Why?
(My gut answer was that no, you don't NEED a virtual destructor
unless the derived class is handling its own dynamically-managed
data.)

In this case, you must answer twice; both the safest way and the technically
correct way. The safest way is "all destructors are virtual unless profiling
reveals the need to remove a virtual". That's safe, because a teammate might
write a class that inherits your class, and then write a 'delete' that uses
a pointer to your class, not the derived class. Deleting such an object,
without a virtual destructor, is undefined behavior.

The technical answer is no, you never are required to make a destructor
virtual, if you know that nobody will ever delete it through a pointer to
the base class.

And the other virtual methods are only indirectly indicated. They don't
influence the technical or semantic decision to make the destructor virtual.
Indirectly, semantically, you should not inherit from a class with no
virtual methods, hence you should never delete a pointer to its base class.

At least the question wasn't "If a destructor releases no resources, must it
be virtual?" That implies the common fallacy that deleting a pointer to the
base class will only create undefined behavior if it creates a leak. The
undefined behavior actually starts at destructor time, regardless what then
leaks.
3. Comment on the following function. What would you change? State
your assumptions:

string & Foo()
{
string default_string = "default answer";
for (vector<node>::iterator iter = mynodes.begin();
iter != mynodes.end();
iter++)
{
cout << iter;
}
return default_string;
}

It returns a reference to a destructed local, so that's undefined.

Next, vector<node> is not typedeffed.

Next, the default_string has nothing to do with the for-loop, which could be
just a decoy. Regardless, you should announce the function does two
independent things and should be split in two.

Next, cout << iter is poorly defined to produce something useless, possibly
a pointer address. If operator<< is defined for 'node', then cout << * iter
might be more useful.

Next, all iterators should always be called 'it'. ;-)
4. When would you use private inheritence? (I have never personally
used this.)

Per /C++ Coding Standards/ by Sutter and Alex A., you should prefer it to
public inheritance.

Consider the Abstract Template Pattern, but where only the derived classes
know they call a secret parent that then, in turn, calls their specialized
methods to help it perform their templated action.

(Warning: That's not a C++ template...)
5. Where in memory is the virtual function lookup table stored?
(I found this one to be way too detailed for me.)

I don't know how Standard this answer is, but it's stored in the initialized
global data segment. This fact (even its accurate version) should never be
used in practice, except in the sickest debugging situations.
6. Consider member initialisation lists. Why are they needed?

Because they explicitly declare intent, to both your colleagues and to the
compiler.
Why are
they considered more efficient than initialising members in the body of
the constructor?

Because the compiler can generate the most efficient code to implement them.
They are defined to occur in the same order as the members appear in the
class's definition, so the compiler could get as efficient as an unrolled
loop to stomp them all in.

Further, some systems can provide a warning if you write them out of order.
This helps your code self-correct.

Next, your constructor's body should be exception neutral and safe. So
putting pointer(NULL) in the member list, and then a pointer=new in the
body, can lead to a safer 'delete' if the constructor then blows. (But the
destructor won't call, so still prefer smart pointers!)

Next, if any member's initialization throws an exception, the stack unwinder
will call the destructor of each fully constructed member, in reverse order.

In general, efficiency is a poor taskmaster. Premature optimization is the
root of all evil. In this case, you may err on the side of efficiency if the
result is also _cognitively_ efficient. Member initialization lists are
easier to comprehend, after you train to recognize them as important parts
of constructors. So follow this rule: Never enter the opening { of a
constructor with any member in an uninitialized state.

You can get that rule easily by only using smart data members, such as smart
pointers and other contained objects with default constructors.
 
C

Carlos Martinez

Digital said:
I'm not the world's greatest C++ programmer, so I had a hard
time with these. Some help would be appreciated.

1. Comment on the declaration of function Bar() below:
class Foo
{
static int Bar(int i) const;
}

(I said that since Bar is a static method, it can only access
static variables, not member variables, so the const is
irrelevant.)

I think it doesn't compile because const is not permitted with static
functions
2. If you have virtual functions in your class, do you need a virtual
destructor? Why?

(My gut answer was that no, you don't NEED a virtual destructor
unless the derived class is handling its own dynamically-managed
data.)

Virtual destructor is needed for calling the apropiate destructor when
delete a pointer-to-base. Heap memory is one reason, but in general, is
necessary when derived class's destructor has something to do.

In general, when yo have virtual functions make destructor virtual.

3. Comment on the following function. What would you change? State
your assumptions:

string & Foo()
{
string default_string = "default answer";
for (vector<node>::iterator iter = mynodes.begin();
iter != mynodes.end();
iter++)
{
cout << iter;
}
return default_string;
}

You are returning a reference to local data of your function. As it's
local it will be destroyed when function is finished.
Usually when you construct a constact value inside a function you make
the variable static. With static variable you can return value by
reference, but I'd make return type const, for fobidding modification on
its value.

Iterator acts like a pointer, thus you must derrefence it:
cout << *iter;

4. When would you use private inheritence? (I have never personally
used this.)

When inheritance is for reusing implementation but hasn't a is-a
relationship. With private inheritance implicit pointer-to-base
conversion is not permitted.
5. Where in memory is the virtual function lookup table stored?
(I found this one to be way too detailed for me.)

I think vtable details are not covered in C++ standard (I'm not sure,
but I think it).
Usually compilers construct it (I don't know where), and pointers and
references have a "link" to it.
I'm not sure on this question, because I don't remember well what I read
about it in the past. I suggest you to read Stanley B. Lippman's "Inside
the C++ object model".
6. Consider member initialisation lists. Why are they needed? Why are
they considered more efficient than initialising members in the body of
the constructor?

They are needed for initializating not-default constructor of base clases.
When you don't initialise a member in an initialisation list, it is
initialised by default, thus when you initialise it inside the body of a
constructor it's initialised twice.
When you initialise a member in the initialisation list, that is the
unique inisialization.
 
M

Murali Krishna

Digital said:
1. Comment on the declaration of function Bar() below:
class Foo
{
static int Bar(int i) const;
}

(I said that since Bar is a static method, it can only access
static variables, not member variables, so the const is
irrelevant.)

I think you are right. const is irrelavant.
2. If you have virtual functions in your class, do you need a virtual
destructor? Why?

(My gut answer was that no, you don't NEED a virtual destructor
unless the derived class is handling its own dynamically-managed
data.)

What about the private data members of base class? They are not
inherited in any case. So how to delete them? I think we need that in
both classes.

I can't understand the third one.
4. When would you use private inheritence? (I have never personally
used this.)

me too. but it is used to make all public and protected members of base
class as private members in derived class. (I think you already know
this)
5. Where in memory is the virtual function lookup table stored?
(I found this one to be way too detailed for me.)

The V-table pointer is generally stored just after the elements of the
base class. That means it is heap. When you see the class size, the
class size will contain member variables size and (no of virtual
functions * pointer size)
6. Consider member initialisation lists. Why are they needed? Why are
they considered more efficient than initialising members in the body of
the constructor?

I am just guessing on the 6th Question.
Why are they needed?
They are generally used to initialize const member variables (also non
const).
why are they more efficient?
really don't know. but normally when you write in the body, you write
statement wise. but here you write using comma operator and assign
through braces. So does this bring any performance? please let me know.

-- Murali Krishna
 
G

Gernot Frisch

It returns a reference to a destructed local, so that's undefined.

Next, vector<node> is not typedeffed.

Next, the default_string has nothing to do with the for-loop, which
could be just a decoy. Regardless, you should announce the function
does two independent things and should be split in two.

Next, cout << iter is poorly defined to produce something useless,
possibly a pointer address. If operator<< is defined for 'node',
then cout << * iter might be more useful.

Next, all iterators should always be called 'it'. ;-)

I'd make that:
static string default_string = "default answer";

and change iter++ to ++iter, since that's a micro optimization.

I don't know how Standard this answer is, but it's stored in the
initialized global data segment. This fact (even its accurate
version) should never be used in practice, except in the sickest
debugging situations.

I think that depends on the compiler. The std does not say anything
about it.
 
S

Stuart Redmann

Murali said:
why are they more efficient?
really don't know. but normally when you write in the body, you write
statement wise. but here you write using comma operator and assign
through braces. So does this bring any performance? please let me know.

The comma operator isn't involved in member initialization lists, that's
just part of C++ syntax (like the semi-colon at the end of each
statement). Member initializations is generally to be prefered, since
members that are initialized in the member initialization list are
initialized by their constructors. If a member is not mentioned in the
member initialization list, it's default constructor will be invoked
(which would assign values that will most likely get overwritten in the
constructor anyway).
Consider the following program and its output:

#include <iostream>
class A
{
int m_a;
public:
A ()
: m_a (0)
{ std::cout << "default constructor of A invoked.";
std::cout << std::endl;}
A (int p_a)
: m_a (p_a)
{ std::cout << "initialization constructor of A invoked.";
std::cout << std::endl;}
A& operator= (int p_a)
{ m_a = p_a;
std::cout << "Assignment operator for A invoked.";
std::cout << std::endl;
return *this;}
};

class B
{
A m_Aobj;
public:
B (int p_b)
: m_Aobj (p_b)
{}
};

class C
{
A m_Aobj;
public:
C (int p_b)
{ m_Aobj = p_b; }
};

int main ()
{
B b (0);
C c (0);
return 0;
}

In those cases where you have no default constructor available, you
cannot get around member initialization lists.
 
M

m_schellens

2. If you have virtual functions in your class, do you need a virtual
What about the private data members of base class? They are not
inherited in any case. So how to delete them? I think we need that in
both classes.

Of course private members are inherited.
The base class methods access them.

The V-table pointer is generally stored just after the elements of the
base class. That means it is heap. When you see the class size, the
class size will contain member variables size and (no of virtual
functions * pointer size)

As stated elsewhere, there is no place where the vtable has to be
stored.
But what you describe would be a very poor implementation.

In most cases, with each instance, there is ONE pointer to a vtable of
that class.
The vtable then contains one pointer per virtual member function and
exists
only once per class.
In g++ this is in the object file (.o) where the destructor of that
class is defined.

It is nice that you want to help, but please comment only on stuff you
really know.
Otherwise your answer just causes confusion.

Regards,
Marc
 
P

Philip Potter

Carlos Martinez said:
When inheritance is for reusing implementation but hasn't a is-a
relationship. With private inheritance implicit pointer-to-base
conversion is not permitted.

But you could just use simple composition anyway - include class B as a data
member of class D instead of as a private parent. I've never found a need
for private inheritance, though the FAQ has a couple of interesting bits on
it.
They are needed for initializating not-default constructor of base clases.
When you don't initialise a member in an initialisation list, it is
initialised by default, thus when you initialise it inside the body of a
constructor it's initialised twice.

Minor nit: It's only initialized once, and then assigned to.

Philip
 
P

Philip Potter

Phlip said:
At least the question wasn't "If a destructor releases no resources, must it
be virtual?" That implies the common fallacy that deleting a pointer to the
base class will only create undefined behavior if it creates a leak. The
undefined behavior actually starts at destructor time, regardless what then
leaks.

Thanks, I didn't know that. Learn something new every day.

Philip
 
C

Carlos Martinez

Philip said:
But you could just use simple composition anyway - include class B as a data
member of class D instead of as a private parent. I've never found a need
for private inheritance, though the FAQ has a couple of interesting bits on
it.

Yes, the same thing may be implemented in different ways. What you say
is called dellegation and is an alternate to inheritance. It's used for
example to reduce multiple inheritance to single inheritance (inherit
from main concept and delegate the others.

Private inheritance is not the only way of reusing implementation, but
it's a way.
I prefer private inheritance over delegation for example when I must
partially export base's interface, with base::myMethod

Minor nit: It's only initialized once, and then assigned to.

Yes. I prefer for simplicity, to create an init member function called
from constructor instead of initialization list, because you centralize
the "reset" of attributes in one function instead of duplicating
initialisation of members in initialisation list of different
constructors and "reset" functions (adding an attribute generates fewer
changes on code because it is located only in a portion of code
(initialisation function)).
But academically, it's a question of performance to prefer
initialisation list over assignment in the body of constructor.
 
K

Kai-Uwe Bux

Phlip said:
Digital Puer wrote:
[snip]
2. If you have virtual functions in your class, do you need a virtual
destructor? Why?
(My gut answer was that no, you don't NEED a virtual destructor
unless the derived class is handling its own dynamically-managed
data.)

In this case, you must answer twice; both the safest way and the
technically correct way. The safest way is "all destructors are virtual
unless profiling reveals the need to remove a virtual". That's safe,
because a teammate might write a class that inherits your class, and then
write a 'delete' that uses a pointer to your class, not the derived class.
Deleting such an object, without a virtual destructor, is undefined
behavior.

The technical answer is no, you never are required to make a destructor
virtual, if you know that nobody will ever delete it through a pointer to
the base class.

And the other virtual methods are only indirectly indicated. They don't
influence the technical or semantic decision to make the destructor
virtual. Indirectly, semantically, you should not inherit from a class
with no virtual methods, hence you should never delete a pointer to its
base class.

This piece of advice is an over-generalization. Inheritance in C++ is
orthogonal to the use of run-time polymorphism and virtual methods. In
fact, the standard library provides various templates especially designed
to be inherited that do neither provide virtual methods nor virtual
destructors; see: unary_function<> or iterator<>.

Your remark is firmly rooted in the OO style of programming, where it makes
perfect sense. However, OO is but one of the various styles of programming
in C++ that make good use of inheritance. Policy based design uses
inheritance often and quite often the policy classes inherited from will
not have virtual methods.

[snip]


Best

Kai-Uwe Bux
 
P

Phlip

Carlos said:
Virtual destructor is needed for calling the apropiate destructor when
delete a pointer-to-base. Heap memory is one reason, but in general, is
necessary when derived class's destructor has something to do.

In general, when yo have virtual functions make destructor virtual.

Those are both the fallacies I posted about. Make the destructor virtual
only because deleting thru a pointer to a base class is undefined. The
presence of non-trivial destructors, or virtual functions, are secondary
considerations.
You are returning a reference to local data of your function. As it's
local it will be destroyed when function is finished.
Usually when you construct a constact value inside a function you make the
variable static. With static variable you can return value by reference,
but I'd make return type const, for fobidding modification on its value.

It would still refer to a destructed object. Just return by copy.
When inheritance is for reusing implementation but hasn't a is-a
relationship. With private inheritance implicit pointer-to-base conversion
is not permitted.

That's just restating the question.
They are needed for initializating not-default constructor of base clases.
When you don't initialise a member in an initialisation list, it is
initialised by default, thus when you initialise it inside the body of a
constructor it's initialised twice.
When you initialise a member in the initialisation list, that is the
unique inisialization.

I prescribe /Effective C++/ by Scott Meyers. It has a good explanation why
member initialization lists should initialize every member that needs
initialization. This is still just a style guideline, not a syntactic rule,
but it's important enough to bring up in a job interview!

Let them know you like clean code.
 
P

Phlip

Murali said:
What about the private data members of base class? They are not
inherited in any case. So how to delete them? I think we need that in
both classes.

That is one of the fallacies I posted about. Make the destructor virtual
only because deleting thru a pointer to a base class is undefined. The
presence of non-trivial destructors, or virtual functions, are secondary
considerations.
The V-table pointer is generally stored just after the elements of the
base class. That means it is heap.

Sometimes it's before, but it's only heap if the entire object is heap.
When you see the class size, the
class size will contain member variables size and (no of virtual
functions * pointer size)

All this is implementation-specific, so if the job doesn't specify a
specific compiler, you must risk announcing the question is non-Standard.

Then answer it almost like you did, and follow with "the vtable can be
global, because it can initialize at startup time, and all objects of a
class may share it."
I am just guessing on the 6th Question.
Why are they needed?
They are generally used to initialize const member variables (also non
const).

They are required on const and reference member data, and on members and
base classes without default constructors, or with constructors you need to
pass custom arguments to.

Also use them on non-const member data.
why are they more efficient?
really don't know. but normally when you write in the body, you write
statement wise. but here you write using comma operator and assign
through braces. So does this bring any performance? please let me know.

Read my first post: "Because they explicitly declare intent, to both your
colleagues and to the
compiler." The more the compiler knows, the better it can optimize. The more
your colleagues know, the faster and safer they can code.
 
P

Phlip

Kai-Uwe Bux said:
This piece of advice is an over-generalization. Inheritance in C++ is
orthogonal to the use of run-time polymorphism and virtual methods. In
fact, the standard library provides various templates especially designed
to be inherited that do neither provide virtual methods nor virtual
destructors; see: unary_function<> or iterator<>.

That proves my point. You inherit those to use templates, not virtuals, to
override methods.

About the only reason to inherit without overriding is to create a
"convenience class". Sometimes, for example, the 'explicit' keyword inside
auto_ptr is annoying, so you inherit auto_ptr<myClass> to create a custom
smart pointer without it.

Actually, that proves my point too. I overrode the constructor on a
template...

Can anyone think of a convenience class that should inherit but doesn't
override something - with virtuals, templates, or some other trick?
Your remark is firmly rooted in the OO style of programming, where it
makes
perfect sense. However, OO is but one of the various styles of programming
in C++ that make good use of inheritance. Policy based design uses
inheritance often and quite often the policy classes inherited from will
not have virtual methods.

I have misplaced my /Effective C++/ book that covers this. Could someone be
a pet and copy in the relevant quote? Scott agrees with us that in rare
cases you inherit without overriding, but in general you don't inherit to
create a "compilable comment", or "so I don't need to delegate to get to the
functions I need."
 
E

Earl Purple

Digital said:
I'm not the world's greatest C++ programmer, so I had a hard
time with these. Some help would be appreciated.

1. Comment on the declaration of function Bar() below:
class Foo
{
static int Bar(int i) const;
}
(I said that since Bar is a static method, it can only access
static variables, not member variables, so the const is
irrelevant.)

The method cannot be const as you have pointed out. Furthermore I would
go on to say that as it is a private method it is generally best to
remove it from the class declaration altogether and put it in the
anonymous namespace of the file that implements Foo. Then it would
still be accessible only by functions of Foo. I am assuming that Bar
does not access private members of Foo in its implementation. If it
does, it may be better to pass those in as extra parameters, by
reference (const if appropriate).
2. If you have virtual functions in your class, do you need a virtual
destructor? Why?
(My gut answer was that no, you don't NEED a virtual destructor
unless the derived class is handling its own dynamically-managed
data.)

Or a protected non-virtual destructor, which would then have the effect
of preventing delete being called on your base class. But since you
have virtual functions so there will be a v-table anyway for the class,
there is no real cost in making the destructor virtual, and anyway you
might want to allow delete to be called on the base class.

Your gut answer was not correct, as others have ponited out.
3. Comment on the following function. What would you change? State
your assumptions:

string & Foo()
{
string default_string = "default answer";
for (vector<node>::iterator iter = mynodes.begin();
iter != mynodes.end();
iter++)
{
cout << iter;
}
return default_string;
}

a. Well obviously you can't return a reference to a local variable. You
can make default_string static but only if you change the return type
to const string, Otherwise do the obvious thing and return by value.
You could also return const char * if you are always going to return
the same thing.

b. I'd change the name from Foo() which is meaningless to some name
that describes what the function does.

c. I wouldn't have using namespace std; anywhere above here so I'd
qualify all the members of std.

d. Assuming you don't really want to output the iterator (and why
should it be streamable, it doesn't have to be a pointer) but you want
to output the node, I'd change the code to:

std::copy( mynodes.begin(), mynodes.end(), std::eek:stream_iterator<node>(
cout ) );

e. This appears to be a class member function. It doesn't modify
anything of the class so make it const.

f. Don't output to cout, give the function an ostream & to output to.

g. And it doesn't look like a template so let's put the implementation
somewhere else. So

std::string MyClass::OutputNodesAndReturnString( std::eek:stream & os )
const
{
// implementation here, with cout replaced with os
}

4. When would you use private inheritence? (I have never personally used this.)

You rarely will, but you would use it when a class is implemented in
terms of another class. The most common occasion is when you might
have:

class Foo : Templ< Foo >

where Templ is a template that is used to implement classes of
different types, but you don't want your users to use it, you only want
them to use Foo.
5. Where in memory is the virtual function lookup table stored?
(I found this one to be way too detailed for me.)

Implementation specific probably, but it's in the "code segment" if
that's what they mean.
6. Consider member initialisation lists. Why are they needed? Why are
they considered more efficient than initialising members in the body of
the constructor?

Should not so much be "why are they needed" rather than "when are they
needed". The are required where you have

a. A base-class or member that has no default constructor, or if the
default constructor is not the one you wish to use to construct it.
b. You have a const member or a reference member (whether const
reference or not).

There is no such thing as initialising members in the body of the
constructor, members are always initialised in the initialiser list.
What you can do, if a member has a default constructor, is use that to
initialise and then modify the member later, usually with assignment.
Constructing with a default constructor then assigning can be less
efficient than constructing with the desired constructor.

If you are referring to pointer members where you need to call new,
beware of exception safety if there is more than one of them and a new
other than the first one fails. Preferably use smart-pointers. I
generally prefer boost::scoped_ptr for this but you can use
std::auto_ptr if you are careful to disable copying and assignment for
the class.
 
K

Kai-Uwe Bux

Phlip said:
That proves my point.

I does not prove your point: You claimed: "you should not inherit from a
class with no virtual methods". When you inherit from
unary_function<int,int>, you inherit from a class with no virtual methods.
Your claim implies, one should not do that. How does the example "prove
your point"?
You inherit those to use templates, not virtuals, to override methods.

You do not inherit from these classes to override methods. You can't because
these classes do not have methods. Example:

class fourier : public std::unary_function<double,double> {

unsigned long frequency;

public:

fourier ( unsigned long f )
: frequency ( f )
{}

double operator() ( double x ) const {
return ( std::sin( x * frequency ) );
}

};

This is a typical way to inherit from std::unary_function<double,double> and
one does not override any methods from the base class. The operator() is
not overridden, it is simply not present in the base class [20.3.1/1].


Your claim would imply, one should not code something like the class
fourier. Yet the standard provides templates like unary_function exactly
for this kind of use.

I simply cannot see at all how this "proves your point".

About the only reason to inherit without overriding is to create a
"convenience class". Sometimes, for example, the 'explicit' keyword inside
auto_ptr is annoying, so you inherit auto_ptr<myClass> to create a custom
smart pointer without it.

Actually, that proves my point too. I overrode the constructor on a
template...

Can anyone think of a convenience class that should inherit but doesn't
override something - with virtuals, templates, or some other trick?

Could you please provide a definition of the term "convenience class"? I
don't know what you mean. In any case, the example above inherits and no
overriding takes place at all (unless, we use the term "override"
differently).

I have misplaced my /Effective C++/ book that covers this. Could someone
be a pet and copy in the relevant quote? Scott agrees with us that in rare
cases you inherit without overriding, but in general you don't inherit to
create a "compilable comment", or "so I don't need to delegate to get to
the functions I need."

Huh? What is a "compilable comment"? Maybe I was not clear: I was talking
about policy based design as explained in Alexandrescu: Modern C++ Design.
In that context, inheritance without overrinding is not rare at all: it's
the rule not the exception.


Best

Kai-Uwe Bux
 
P

Phlip

Philip said:
No it wouldn't. It's static.

Since when do I have to read an entire paragraph before replying to it???

;-)

Back on subject, excessive return value shenanigans are a sign of Premature
Optimization. Just rely on return-value optimization, then on any
copy-on-write capacity inside the string.
 
W

werasm

Phlip said:
Digital said:
I'm not the world's greatest C++ programmer, so I had a hard
time with these. Some help would be appreciated. [snip]
2. If you have virtual functions in your class, do you need a virtual
destructor? Why?
[snip]

In this case, you must answer twice; both the safest way and the technically
correct way. The safest way is "all destructors are virtual unless profiling
reveals the need to remove a virtual". That's safe, because a teammate might
write a class that inherits your class, and then write a 'delete' that uses
a pointer to your class, not the derived class. Deleting such an object,
without a virtual destructor, is undefined behavior.

The technical answer is no, you never are required to make a destructor
virtual, if you know that nobody will ever delete it through a pointer to
the base class.

This can of course be enforced by making the destructor protected and
non virtual. Therefore, when a (base) class has virtual functions
(methods), its destructor should be either public and virtual, or
protected and non-virtual, depending on whether one intends to delete
via the applicable interface or not.

Derived classes can of course static_cast their this pointer to that of
their base and then delete themselves, but I don't think bases have to
guard agains that kind of (absurd) behaviour :-0.

[snip]

Agree, for the most.

Regards,

Werner
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top