I'm not even sure what that argument means. What is a "user" of your
class?
Another programmer? An end-user? Or code that makes calls to your
class's
code? I don't see what having "never seen them" means in relation to
any of
those cases. And I still don't see why you need to construct a new
instance
of an object if the object already exists, because all that is doing is
making a copy of some existing object, and your limited example of using
that copy does not justify that action.
First of all: I highly appreciate all the efforts (yours and those of
Victor and Karl Heinz) to help me. This discussion provided me with a
number of good points to think about in my design. But I think I see that
my limited example may not be sufficient. And my employer might not
appreciate if I post the original code ;-). I tried to invent a simple
case and now we are more into a discussion of that case's design than into
my original problem. I'll still try to explain what I can. If it's more
confusing than illuminating, just tell me I'm a hopeless case and abort
the discussion...
The "users" are other programmers. At the beginning of their sourcecode
they (naturally) don't have any BOOK objects. But the map of books is
already filled. Maybe they even will not be allowed to add other books
(the constructor taking enough arguments to create a fully defined BOOK
may be private). So how do they make BOOK objects? I proposed a
constructor taking a title that returns a copy of an existing book:
BOOK tolkien("The Hobbit");
If I understand Victor correctly, his point is that a constructor should
create something new and not return something existing. I suppose he would
prefer using a function like findByTitle() that returns an existing book.
If findByTitle() is static, as Victor proposed, that would work for
nameless objects:
cout << BOOK::findByTitle("The Hobbit").author;
But how do I create named objects? I don't expect to have a default
constructor (is there a default book?). So the only way to create a named
object would be to copy-construct from a nameless object returned by
findByTitle():
BOOK tolkien( findByTitle("The Hobbit") );
Plus, you still haven't explained what a LIBRARY is (nor why your
collection
of BOOKs is contained in a BOOK object instead of a LIBRARY object).
O.k., forget about LIBRARY. I invented it quickly and it was a bad
example. Objects of my second class contain a subset of by "books",
LIBRARY would be more like a superset. I'll try to invent something better
a few lines down
My collection of BOOKs is NOT contained in any BOOK object. It's static,
so it's contained in the class. I think that's not too bad -- each object
contains a single book, the class has a collection of all my books.
If my second class contains a subset of my books, maybe a good example
could be BOOKSHELF or GENRE. Let's try GENRE. My only point here was, if
GENRE has a method addBook() that takes a BOOK as an argument, then with
the constructor I proposed I could say:
GENRE fantasy;
fantasy.addBook("The Hobbit");
otherwise I have to say
fantasy.addBook( findByTitle("The Hobbit") );
I like that first form, but that's just personal preference.
I don't understand what you mean when you say "even when findByTitle is
used
instead of a constructor". A copy-constructor takes a const reference
to an
existing object (a BOOK) and creates a new one based on that. It's
irrelevant how you obtained that reference.
Victor wrote: "why do I need to construct another object from a single
'title' when I already have one sitting in the map<string, BOOK>?" My
point was: The objects in the map are nameless. If somebody wants a named
BOOK object, he will need some kind of contructor to create it. Either the
contructor taking a title, as I proposed, or a copy constructor as
mentioned above.
Is findByTitle a static function??? Why are you specifying
BOOK::findByTitle, and not something like someBook.findByTitle? This
seems
to point tight back to the use of another class (LIBRARY) to hold the
collection instead of an individual BOOK.
1. findByTitle() wasn't static in my first post. But I think Victor
pointed out correctly that it should be.
2. How do I construct your someBook?
Assuming that findByTitle returns a
reference to an existing BOOK object (does it?), Yes, it does.
then you might want to do this:
BOOK& someOtherBook = someBook.findByTitle("The Hobbit");
cout << someOtherBook.author << endl;
cout << someOtherBook.price << endl;
There's no construction going on here at all, and I only need the
findByTitle call once.
(Or if findByTitle returns a pointer, then use a pointer instead of a
reference...but my point is the same.)
I'm a bit reluctant to use pointers or references to objects in my map. I
don't think that current implementations will ever reallocate memory as
they grow. The nodes of the underlying tree have pointers to parent, left
and right, so it's sufficient to manipulate those pointers during groth.
But is this behavior guaranteed by any standard?
How was someBook created? Maybe like this:
BOOK someBook( findByTitle("Programming Perl") );
Now does it make sense to say:
someBook.findByTitle("The Hobbit"); ?
I would prefer to use findByTitle() as a static function:
BOOK::findByTitle("The Hobbit");
Without a more realistic sample of your code and the problem you face,
(especially showing the context in which you feel the need to use a newly
constructed object like that instead of a pointer or reference), I doubt
we can tell you any more than you already know.
O.k.. I just thought that I might have overseen some very simple solution.
Again, thank you for this discussion. If forced me to think again about
some aspects of my design and that's always good!
Wolfram