QUIZ Friends class Y; Is a forward declaration neeed here?
QUIZ Friends
QUIZ Friends - CONCLUSION Forward (a.k.a. incomplete) declarations are needed only when we declare member functions as friends. They are not needed for global functions or entire structs/classes.
QUIZ Why is it sometimes not a good idea to place the private part of the interface in a header file?
Example projects where we don t want the implementation visible to the client programmer: The library header file may show proprietary info. that the company doesn t want available to competitors. Security (e.g. an encryption algorithm) don t want to expose any clues in a header file that might help people crack the code. Library is used in a hostile environment, where the programmers will try to directly access the private components anyway, using pointers and casting.
QUIZ Why can a.cpp file be made more secure than a header file?
QUIZ Why can a.cpp file be made more secure than a header file? Because it can be provided in the library in an already-compiled form, so the client programmers don t have access to the source code.
QUIZ What is the fragile base-class problem?
QUIZ The fragile base-class problem: Any time we make a change to a class (public interface or private member declarations), it is necessary to recompile all files that include that header file. For a large project in its early stages this can be very unwieldy because the underlying implementation may change often; if the project is very big, the time for compiles can prohibit rapid turnaround.
QUIZ What is a handle class?
QUIZ What is a handle class? A class that is accessed only through an opaque pointer; the class interface and definition are not available to the client programmer.
QUIZ How is a handle class implemented in C++?
QUIZ How is a handle class implemented in C++? With a forward declaration and a pointer:
Ch. 6: Initialization & Cleanup
Main ideas from chs. 4 and 5 Encapsulation (functions inside struct/class) Access control (hiding)
Two more safety issues: A large segment of C bugs occur when the programmer forgets to initialize or clean up a variable. This is especially true with C libraries, when client programmers don t know how to initialize a struct, or even that they must. (Libraries often do not include an initialization function, so the client programmer is forced to initialize the struct by hand.)
Two more safety issues: C programmers are comfortable with forgetting about variables once they are finished, so any cleaning up that may be necessary for a library s struct is often missed. What if we allocated memory dynamically for a large array? Memory leaks!
Guaranteed initialization with the constructor Both the Stash and Stack classes defined previously have a function called initialize( ), which hints by its name that it should be called before using the object in any other way. Unfortunately, this means the client programmer must ensure proper initialization by calling it.
Guaranteed initialization with the constructor In C++, initialization is too important to leave to the client programmer. The class designer can guarantee initialization of every object by providing a special function called the constructor. If a class has a constructor, the compiler automatically calls that constructor at the point an object is created, before client programmers can get their hands on the object.
Note that the constructor is in the public section of the interface! Name of constructor is the same as name of class.
What happens if we make the constructor private?
It is still possible to create objects of this class, but we have to use other member functions in Test, of friend functions. Conclusion: The constructor should be public (unless we have a good reason to the contrary).
the same thing happens as if a were an int: storage is allocated for the object. But [unlike an int] when the program reaches the sequence point (point of execution) where a is defined, the constructor is called automatically. That is, the compiler quietly inserts the call to X::X( ) for the object a at the point of definition.
Like any member function, the first (secret) argument to the constructor is the this pointer the address of the object for which it is being called. In the case of the constructor, however, this is pointing to an un-initialized block of memory, and it s the job of the constructor to initialize this memory properly.
QUIZ
QUIZ 3. Modify Exercise 1 so that the class contains an int member. Modify the constructor so that it takes an int argument that it stores in the class member. The constructor should print out the int value as part of its message, so you can see the objects as they are created. Create 2 objects of this class, with different arguments passed to the constructor.
Both constructor and destructor are unusual functions: they have no return value. This is distinctly different from a void return value, in which the function returns nothing but you still have the option to make it something else.
[ ] the compiler always makes these function calls itself, to make sure they happen properly. If there were a return value, and if you could select your own, the compiler would somehow have to know what to do with the return value, or the client programmer would have to explicitly call constructors and destructors, which would eliminate their safety.
We stop before the section Guaranteed cleanup with the destructor EOL 17
QUIZ What (if anything) is wrong with this code?
QUIZ How are constructors different from regular member functions?
QUIZ How are constructors different from regular member functions? They have the same name as the class They have no return type They are called automatically when objects are declared
QUIZ Can C++ structs have constructors?
QUIZ Can C++ structs have constructors? Yes, remember that there s only one difference between structs and classes in C++!
Guaranteed cleanup with the destructor No return type No arguments! Tilde Same name as the class
The destructor is called automatically by the compiler when the object goes out of scope. You can see where the constructor gets called by the point of definition of the object, but the only evidence for a destructor call is the closing brace of the scope that surrounds the object.
~Tree() is called here
QUIZ
QUIZ How are constructors and destructors: Similar? Different?
[ ] the destructor is still called, even when you use goto to jump out of a scope. (goto still exists in C++ for backward compatibility with C and for the times when it comes in handy.) You should note that a nonlocal goto, implemented by the Standard C library functions setjmp( ) and longjmp( ), doesn t cause destructors to be called. https://en.wikipedia.org/wiki/setjmp.h
Elimination of the definition block In C, you must always define all the variables at the beginning of a block, after the opening brace. [ ] it s good programming style. However: It has always seemed inconvenient to me to pop back to the beginning of a block every time I need a new variable. I find code more readable when the variable definition is close to its point of use.
Elimination of the definition block In C++, however, there s a significant problem in being forced to define all objects at the beginning of a scope: If a constructor exists, it must be called when the object is created. However, if the constructor takes one or more initialization arguments, how do you know you will have that initialization information at the beginning of a scope?
Doesn t matter whether we use braces or not the scope is always the body of the loop. (Of course, w/o braces, the body of the loop is only one command.)
QUIZ What will this code print?
Watch out for local variables that hide variables from the enclosing scope. In general, using the same name for a nested variable and a variable that is global to that scope is confusing and error-prone. I.e. have the same name as
I find small scopes an indicator of good design. If you have several pages for a single function, perhaps you re trying to do too much with that function. More granular functions are not only more useful, but they also make it easier to find bugs.
To make sure all objects are properly initialized, the compiler even checks to make sure that you don t put the object definition (and thus the constructor call) where the sequence point only conditionally passes through it, such as in a switch statement or somewhere a goto can jump past it.
Stash with constructors and destructors
Stack with constructors & destructors will be covered in the lab
Aggregate initialization An aggregate is just what it sounds like: a bunch of things clumped together. This definition includes aggregates of mixed types, like structs and classes. An array is an aggregate of a single type. Initializing aggregates can be error-prone and tedious. C++ aggregate initialization makes it much safer.
All these cases are identical to C:
All these cases are identical to C:
If any of the data members are private (which is typically the case for a well-designed class in C++), or even if everything s public but there s a constructor, things are different:
An example with constructors having multiple arguments:
Default constructors
You might think that the compiler-synthesized constructor should do some intelligent initialization, like setting all the memory for the object to zero. But it doesn t that would add extra overhead [ ] If you want the memory to be initialized to zero, you must do it yourself by writing the default constructor explicitly.
Another reason for lazy default constructors is that, in many cases, it is not clear what the default value should be for an object! E.g. How should be dates initialized?
Although the compiler will create a default constructor for you, the behavior of the compilersynthesized constructor is rarely what you want. You should treat this feature as a safety net, but use it sparingly. In general, you should define your constructors explicitly and not allow the compiler to do it for you.
Ambiguity: In the next chapter we shall encounter overloaded constructors:
There is no homework for ch. 6 assigned today! One homework will be assigned for 6 and 7 together. EOL 18