R. Clayton (rclayton@monmouth.edu)
(no date)
What is your opinion on writing trivial methods completely within the .h
file?
class toy {
public:
int getname() {return num;};
.
.
.
};
I have three problems with it, which are (in increasing order of seriousness
but decreasing order of practical effect):
First, in keeping with the wonderful way that C++ overloads meanings, defining
(as opposed to declaring) a method in a class implicitly makes that method
available for in-lining by the compiler. This isn't really a problem as long
as the method remains trivial (and you don't, for most compilers, use the
proper optimization to request in-lining), but methods tend to grow in size,
which could lead to code-bloat when in-lining is used.
(Here I'm assuming that it was not your intention to in-line, but rather to
avoid writing a second .cc file that actually contains the method definitions.
If you really meant to in-line, then you probably know what you're doing and
understand the problems of method-size growth.)
Second, related to the first, every time you do change the method, you force a
re-compile of every file that includes the .h. Given the size of the
assignments in 509, this is not a problem, as long as you understand and use
make. If you don't understand or don't use make, then even the 509 assignments
can give you problems if you forget to re-compile one of the files; the errors
that result from partial re-compilations are wicked and subtle.
(As an aside, one of the reasons I repeatedly stress not including .cc files in
.h files is that lazy students - students who won't learn or use make - tend to
solve the re-compilation problem by including all their source files in one
.h.)
On the other hand, if you move the method definition into a separate .cc file,
then any changes made to the method only require that the associated .cc file
be recompiled (but you lose the ability to in-line if that's important).
Finally, I get nervous when I see a class that contains a lot of field
accessors. It suggests to me that the class designer didn't have a good grasp
on the abstractions the class is supposed to representing, and so just punted
by letting everybody have access to everything. This, to me, is lazy and
careless design.
Here's an example adapted from my solution to the first assignment. I have a
tag class to represent tags, and I originally designed it with two getter
accessors (setters not being needed):
class tag {
public:
string get_name() const { return name; }
bool get_open() const { return open; }
private:
const string name;
const bool open;
};
As my code used tags, this was poor design, because I don't really care what
the name of a tag is, I only care if two tags have the same name. I can raise
the level of the abstraction provided by the tag class if I replace the name
getter with a test for sameness (my code did need to know of a tag was an open
or close tag, so the get_open() accessor was at the proper level of
abstraction):
class tag {
public:
bool same(const tag & t) const { return name == t.name; }
bool get_open() const { return open; }
private:
const string name;
const bool open;
};
I should point out, however, that this view of accessor methods is
controversial, and will probably become more so as C# (which automatically
defines field accessors) becomes more popular. I'm willing to defend this
point of view, but you should understand that it is a point of view that
requires defending.
Also, there used to be some shorthand for if/then/else statements that
involved question marks and colons. I can't seem to find the syntax for it -
is that still valid in C++ or has that been deprecated?
See Section 2.6, The if/else Selection Structure, in Deitel and Deitel (third
edition, but probably the same for other editions too). Or see page 45 in
Koenig and Moo (which isn't part of this section's reading assignment).
This archive was generated by hypermail 2.0b3 on Mon May 03 2004 - 17:00:06 EDT