Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Professional C++ [eng].pdf
Скачиваний:
284
Добавлен:
16.08.2013
Размер:
11.09 Mб
Скачать

Chapter 8

Here the method copies the values:

return (*this);

}

Finally it returns *this, as explained previously.

The syntax for overriding operator= may seem a strange at first. You probably felt the same way when you first learned about some other C or C++ syntax, such as switch statements — the syntax just doesn’t feel right. With operator=, you’re getting into some deep language features. You are actually changing the meaning of the = operator. This powerful capability unfortunately requires some unusual syntax.

Don’t worry, you’ll get used to it!

Distinguishing Copying from Assignment

It is sometimes difficult to tell when objects are initialized with a copy constructor rather than assigned to with the assignment operator. Consider the following code:

SpreadsheetCell myCell(5);

SpreadsheetCell anotherCell(myCell);

AnotherCell is constructed with the copy constructer.

SpreadsheetCell aThirdCell = myCell;

aThirdCell is also constructed with the copy constructer. This line does not call operator=! This syntax is just another way to write: SpreadsheetCell aThirdCell(myCell);

anotherCell = myCell; // Calls operator= for anotherCell.

Here anotherCell has already been constructed, so the compiler calls operator=:

= does not always mean assignment! It can also be shorthand for copy construction when used on the same line as the variable declaration.

Objects as Return Values

When you return objects from functions or methods, it is sometimes difficult to see exactly what copying and assignment is happening. Recall that the code for getString() looks like this:

string SpreadsheetCell::getString()

{

return (mString);

}

180

Gaining Proficiency with Classes and Objects

Now consider the following code:

SpreadsheetCell myCell2(5); string s1;

s1 = myCell2.getString();

When getString() returns mString, the compiler actually creates an unnamed temporary string object by calling a string copy constructor. When you assign this result to s1, the assignment operator is called for s1 with the temporary string as a parameter. Then, the temporary string object is destroyed. Thus, the single line of code invokes the copy constructor and the assignment operator (for two different objects).

In case you’re not confused enough, consider this code:

SpreadsheetCell myCell3(5); string s2 = myCell3.getString();

In this case, getString() still creates a temporary unnamed string object when it returns mString. But now s1 gets its copy constructor called, not its assignment operator.

If you ever forget the order in which these things happen or which constructor or operator is called, you can easily figure it out by temporarily including helpful output in your code or by stepping through it with a debugger.

Copy Constructors and Object Members

You should also note the difference between assignment and copy constructor calls in constructors. If an object contains other objects, the compiler-generated copy constructor calls the copy constructors of each of the contained objects recursively. When you write your own copy constructor, you can provide the same semantics by using an initializer list, as shown previously. If you omit a data member from the initializer list, the compiler performs default initialization on it (a call to the 0-argument constructor for objects) before executing your code in the body of the constructor. Thus, by the time the body of the constructor executes, all object data members have already been initialized.

You could write your copy constructor without using an initialization list, like this:

SpreadsheetCell::SpreadsheetCell(const SpreadsheetCell& src)

{

mValue = src.mValue; mString = src.mString;

}

However, when you assign values to data members in the body of the copy constructor, you are using the assignment operator on them, not the copy constructor, because they have already been initialized, as described previously.

181

Chapter 8

Summar y

This chapter covered the fundamental aspects of C++’s facilities for object-oriented programming: classes and objects. It first reviewed the basic syntax for writing classes and using objects, including access control. Then, it covered object life cycles: when objects are constructed, destructed, and assigned, and what methods those actions invoke. The chapter included details of the constructor syntax, including initializer lists. It also specified exactly which constructors the compiler writes for you, and under what circumstances, and explained that default constructors take no arguments.

For some of you, this chapter was mostly review. For others, it hopefully opened your eyes to the world of object-oriented programming in C++. In any case, now that you are proficient with objects and classes you can learn, read Chapter 9 to learn more about their tricks and subtleties.

182

Mastering Classes

and Objects

Chapter 8 helped you gain proficiency with classes and objects. Now it’s time to master their subtleties so you can use them to their full potential. By reading this chapter, you will learn how to manipulate and exploit some of the most complicated aspects of the C++ language in order to write safe, effective, and useful classes.

This chapter provides a detailed tutorial of advanced topics, including dynamic memory allocation in objects, static methods and members, const methods and members, reference and const reference members, method overloading and default parameters, inline methods, nested classes, friends, operator overloading, pointers to methods and members, and separate interface and implementation classes.

Many of the concepts in this chapter arise in advanced C++ programming, especially in the standard template library.

Dynamic Memor y Allocation in Objects

Sometimes you don’t know how much memory you will need before your program actually runs. As you know, the solution is to dynamically allocate as much space as you need during program execution. Classes are no exception. Sometimes you don’t know how much memory an object will need when you write the class. In that case, the object should dynamically allocate memory.

Dynamically allocated memory in objects provides several challenges, including freeing the memory, handling object copying, and handling object assignment.