One common coding practice to help avoid such confusion is to use an m_ prefix to identify data member names:
class Stock
{
private:
string m_company;
long m_shares;
...
Another common practice is to use an underbar suffix for member names:
class Stock
{
private:
string company_;
long shares_;
...
With either convention, you then can use company and shares as the parameter names in the public interface.
Using Constructors
C++ provides two ways to initialize an object by using a constructor. The first is to call the constructor explicitly:
Stock food = Stock("World Cabbage", 250, 1.25);
This sets the company member of the food object to the string "World Cabbage", the shares member to 250, and so on.
The second way is to call the constructor implicitly:
Stock garment("Furry Mason", 50, 2.5);
This more compact form is equivalent to the following explicit call:
Stock garment = Stock("Furry Mason", 50, 2.5));
C++ uses a class constructor whenever you create an object of that class, even when you use new for dynamic memory allocation. Here’s how to use the constructor with new:
Stock *pstock = new Stock("Electroshock Games", 18, 19.0);
This statement creates a Stock object, initializes it to the values provided by the arguments, and assigns the address of the object to the pstock pointer. In this case, the object doesn’t have a name, but you can use the pointer to manage the object. We’ll discuss pointers to objects further in Chapter 11.
Constructors are used differently from the other class methods. Normally, you use an object to invoke a method:
stock1.show(); // stock1 object invokes show() method
However, you can’t use an object to invoke a constructor because until the constructor finishes its work of making the object, there is no object. Rather than being invoked by an object, the constructor is used to create the object.
Default Constructors
A
Stock fluffy_the_cat; // uses the default constructor
Hey, Listing 10.3 already did that! The reason this statement works is that if you fail to provide any constructors, C++ automatically supplies a default constructor. It’s an implicit version of a default constructor, and it does nothing. For the Stock class, the default constructor would look like this:
Stock::Stock() { }
The net result is that the fluffy_the_cat object is created with its members uninitialized, just as the following creates x without providing a value for x:
int x;
The fact that the default constructor has no arguments reflects the fact that no values appear in the declaration.
A curious fact about default constructors is that the compiler provides one only if you don’t define any constructors. After you define any constructor for a class, the responsibility for providing a default constructor for that class passes from the compiler to you. If you provide a nondefault constructor, such as Stock(const string & co, long n, double pr), and don’t provide your own version of a default constructor, then a declaration like this becomes an error:
Stock stock1; // not possible with current constructor
The reason for this behavior is that you might want to make it impossible to create uninitialized objects. If, however, you wish to create objects without explicit initialization, you must define your own default constructor. This is a constructor that takes no arguments. You can define a default constructor two ways. One is to provide default values for all the arguments to the existing constructor:
Stock(const string & co = "Error", int n = 0, double pr = 0.0);
The second is to use function overloading to define a second constructor, one that has no arguments:
Stock();
You can have only one default constructor, so be sure that you don’t do both. Actually, you should usually initialize objects in order to ensure that all members begin with known, reasonable values. Thus, a user-provided default constructor typically provides implicit initialization for all member values. For example, this is how you might define one for the Stock class:
Stock::Stock() // default constructor
{
company = "no name";
shares = 0;
share_val = 0.0;
total_val = 0.0;
}
Tip
When you design a class, you should usually provide a default constructor that implicitly initializes all class members.
After you’ve used either method (no arguments or default values for all arguments) to create the default constructor, you can declare object variables without initializing them explicitly:
Stock first; // calls default constructor implicitly
Stock first = Stock(); // calls it explicitly
Stock *prelief = new Stock; // calls it implicitly
However, you shouldn’t be misled by the implicit form of the nondefault constructor:
Stock first("Concrete Conglomerate"); // calls constructor