Digital Puer wrote:
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::ostream_it erator<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::Output NodesAndReturnS tring( std::ostream & os )
const
{
// implementation here, with cout replaced with os
}
h. Last thing. What is node anyway? vector<nodeis what construct? Are
we reinventing any wheels here?
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_p tr for this but you can use
std::auto_ptr if you are careful to disable copying and assignment for
the class.