views:

97

answers:

3

Toward the end of Chapter 16 of the "C++ Primer" I encountered the following code (I've removed a bunch of lines):

class Sales_item {
public:
    // default constructor: unbound handle
    Sales_item(): h() { }
private:
    Handle<Item_base> h;   // use-counted handle
};

My problem is with the Sales_item(): h() { } line.

For the sake of completeness, let me also quote the parts of the Handle class template that I think are relevant to my question (I think I don't need to show the Item_base class):

template <class T> class Handle {
public:
    // unbound handle
    Handle(T *p = 0): ptr(p), use(new size_t(1)) { }
private:
    T* ptr;          // shared object
    size_t *use;     // count of how many Handles point to *ptr
};

I would have expected something like either:

a) Sales_item(): h(0) { } which is a convention the authors have used repeatedly in earlier chapters, or

b) Handle<Item_base>() if the intention was to invoke the default constructor of the Handle class.

Instead, what the book has is Sales_item(): h() { }. My gut reaction is that this is a typo, since h() looks suspiciously similar to a function declaration. On the other hand, I just tried compiling under g++ and running the example code that uses this class and it seems to be working correctly. Any thoughts?

EDIT: All good answers, thanks! I have in the intervening 30 minutes tracked down a relevant quote from chapter 12 of the same book: "When we initialize a member of class type, we are specifying arguments to be passed to one of the constructors of that member's type. We can use any of that type's constructors." And as you all pointed out, in this case we are passing zero arguments.

+5  A: 

What you have with Sales_item(): h() { } is a constructor with a data member initialization.

I would have expected something like either:

a) Sales_item(): h(0) { } which is a convention the authors have used repeatedly in earlier chapters, or

This isn't necessary because the constructor of Handle<Item_base>() can be invoked without an argument. (Its one argument has a default value, so it can be omitted.)

b) Handle<Item_base>() if the intention was to invoke the default constructor of the Handle class.

This is simply incorrect syntax. That syntax is used for base classes and there it is fine, since any class can inherit only once from Handle<Item_base>(). However, it can have many data elements of that type, so in order to initialize the right data member, its name is used rather than its type.


That's a very good book you're learning from, BTW. Once you're through it, you might want to look at The Definitive C++ Guide and List for more good input.

sbi
You're absolutely right about point b. It's clear from my edits that I wasn't quite sure what I was getting at with this one.
Alexandros Gezerlis
+1  A: 

h is the name of a member variable of Sales_item, and its class Handle has a constructor with a default parameter, so h() constructs the member properly. It is equivalent to h(0).

Péter Török
+2  A: 

The code is completely correct - the h() means use the default constructor to construct h. In this case it is also unecessary, as the default constructor will be used if you don't supply an explicit initialisation. A default constructor is any constructor that can be called without arguments, which the handle class has, due to it's defaulted argument value.

anon