If you don t write a constructor for a class object, C# writes one for you
Suppose that you want to assemble your own PC, you go to a hardware store and pick up a motherboard, a processor, some RAMs, a hard disk, a casing, a power supply, and put them together. You turn on the power, and the PC runs. You need not worry whether the motherboard is a 4-layer or 6-layer board, whether the hard disk has 4 or 6 plates; 3 inches or 5 inches in diameter, whether the RAM is made in Japan or Korea, and so on. You simply put the hardware components together and expect the machine to run. Of course, you have to make sure that you have the correct interfaces, i.e., you pick an IDE hard disk rather than a SCSI hard disk, if your motherboard supports only IDE; you have to select RAMs with the correct speed rating, and so on. Nevertheless, it is not difficult to set up a machine from hardware components. Similarly, a car is assembled from parts and components, such as chassis, doors, engine, wheels, brake, and transmission. The components are reusable, e.g., a wheel can be used in many cars (of the same specifications). Hardware, such as computers and cars, are assembled from parts, which are reusable components. How about software? Can you "assemble" a software application by picking a routine here, a routine there, and expect the program to run? The answer is obviously no! Unlike hardware, it is very difficult to "assemble" an application from software components. Since the advent of computer 60 years ago, we have written tons and tons of programs. However, for each new application, we have to re-invent the wheels and write the program from scratch. Why re-invent the wheels? Traditional Procedural-Oriented languages![]() Can we do this in traditional procedural-oriented programming language such as C, Fortran, Cobol, or Pascal? Traditional procedural-oriented languages (such as C and Pascal) suffer some notable drawbacks in creating reusable software components:
In brief, the traditional procedural-languages separate the data structures and algorithms of the software entities. In the early 1970s, the US Department of Defense (DoD) commissioned a task force to investigate why its IT budget always went out of control; but without much to show for. The findings are:
The task force proposed to make software behave like hardware OBJECT. Subsequently, DoD replaces over 450 computer languages, which were then used to build DoD systems, with an object-oriented language called Ada. Object-Oriented Programming Languages![]() Object-oriented programming (OOP) languages are designed to overcome these problems.
![]() As an example, suppose you wish to write a computer soccer games (which I consider as a complex application). It is quite difficult to model the game in procedural-oriented languages. But using OOP languages, you can easily model the program accordingly to the "real things" appear in the soccer games.
Most importantly, some of these classes (such as Circle(double r = 1.0, string c = "red") { radius = r; color = c; }0 and Circle(double r = 1.0, string c = "red") { radius = r; color = c; }1) can be reused in another application, e.g., computer basketball game, with little or no modification. Benefits of OOPThe procedural-oriented languages focus on procedures, with function as the basic unit. You need to first figure out all the functions and then think about how to represent data. The object-oriented languages focus on components that the user perceives, with objects as the basic unit. You figure out all the objects by putting all the data and operations that describe the user's interaction with the data. Object-Oriented technology has many benefits:
OOP BasicsClasses & InstancesClass: A class is a definition of objects of the same kind. In other words, a class is a blueprint, template, or prototype that defines and describes the static attributes and dynamic behaviors common to all objects of the same kind. Instance: An instance is a realization of a particular item of a class. In other words, an instance is an instantiation of a class. All the instances of a class have similar properties, as described in the class definition. For example, you can define a class called " Circle(double r = 1.0, string c = "red") { radius = r; color = c; }2" and create three instances of the class " Circle(double r = 1.0, string c = "red") { radius = r; color = c; }2" for " Circle(double r = 1.0, string c = "red") { radius = r; color = c; }4", " Circle(double r = 1.0, string c = "red") { radius = r; color = c; }5" and " Circle(double r = 1.0, string c = "red") { radius = r; color = c; }6". The term "object" usually refers to instance. But it is often used quite loosely, which may refer to a class or an instance. A Class is a 3-Compartment Box encapsulating Data and Functions![]() A class can be visualized as a three-compartment box, as illustrated:
In other words, a class encapsulates the static attributes (data) and dynamic behaviors (operations that operate on the data) in a box. Class Members: The data members and member functions are collectively called class members. The followings figure shows a few examples of classes: ![]() The following figure shows two instances of the class Circle(double r = 1.0, string c = "red") { radius = r; color = c; }2, identified as " Circle(double r = 1.0, string c = "red") { radius = r; color = c; }8" and " Circle(double r = 1.0, string c = "red") { radius = r; color = c; }9". ![]() Unified Modeling Language (UML) Class and Instance Diagrams: The above class diagrams are drawn according to the UML notations. A class is represented as a 3-compartment box, containing name, data members (variables), and member functions, respectively. classname is shown in bold and centralized. An instance (object) is also represented as a 3-compartment box, with instance name shown as Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }0 and underlined. Brief Summary
Class DefinitionIn C++, we use the keyword Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }1 to define a class. There are two sections in the class declaration: Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 and Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }3, which will be explained later. For examples, Class Naming Convention: A classname shall be a noun or a noun phrase made up of several words. All the words shall be initial-capitalized (camel-case). Use a singular noun for classname. Choose a meaningful and self-descriptive classname. For examples, Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }4, Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }5, Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }6, Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }7 and Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }8. Creating Instances of a ClassTo create an instance of a class, you have to:
For examples, suppose that we have a class called Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9, we can create instances of Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 as follows: Alternatively, you can invoke the constructor explicitly using the following syntax: Dot (.) OperatorTo reference a member of a object (data member or member function), you must:
For example, suppose that we have a class called Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9, with two data members ( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 255) and two functions ( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 256 and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 257). We have created three instances of the class Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9, namely, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 259, double radius = 1.0; // error: ISO C++ forbids in-class initialization of non-const static member 'radius'0 and double radius = 1.0; // error: ISO C++ forbids in-class initialization of non-const static member 'radius'1. To invoke the function 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 257, you must first identity the instance of interest, says double radius = 1.0; // error: ISO C++ forbids in-class initialization of non-const static member 'radius'0, then use the dot operator, in the form of double radius = 1.0; // error: ISO C++ forbids in-class initialization of non-const static member 'radius'4, to invoke the 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 257 function of instance double radius = 1.0; // error: ISO C++ forbids in-class initialization of non-const static member 'radius'0. For example, Calling 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 257 without identifying the instance is meaningless, as the radius is unknown (there could be many instances of Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 - each maintaining its own radius). In general, suppose there is a class called double radius = 1.0; // error: ISO C++ forbids in-class initialization of non-const static member 'radius'9 with a data member called Circle(double radius = 1.0, string color = "red");0 and a member function called Circle(double radius = 1.0, string color = "red");1. An instance called Circle(double radius = 1.0, string color = "red");2 is constructed for double radius = 1.0; // error: ISO C++ forbids in-class initialization of non-const static member 'radius'9. You use Circle(double radius = 1.0, string color = "red");4 and Circle(double radius = 1.0, string color = "red");5. Data Members (Variables)A data member (variable) has a name (or identifier) and a type; and holds a value of that particular type (as descried in the earlier chapter). A data member can also be an instance of a certain class (to be discussed later). Data Member Naming Convention: A data member name shall be a noun or a noun phrase made up of several words. The first word is in lowercase and the rest of the words are initial-capitalized (camel-case), e.g., Circle(double radius = 1.0, string color = "red");6, Circle(double radius = 1.0, string color = "red");7, Circle(double radius = 1.0, string color = "red");8, Circle(double radius = 1.0, string color = "red");9 and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 350. Take note that variable name begins with an lowercase, while classname begins with an uppercase. Member FunctionsA member function (as described in the earlier chapter):
Member Function Naming Convention: A function name shall be a verb, or a verb phrase made up of several words. The first word is in lowercase and the rest of the words are initial-capitalized (camel-case). For example, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 256, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 352. Take note that data member name is a noun (denoting a static attribute), while function name is a verb (denoting an action). They have the same naming convention. Nevertheless, you can easily distinguish them from the context. Functions take arguments in parentheses (possibly zero argument with empty parentheses), but variables do not. In this writing, functions are denoted with a pair of parentheses, e.g., 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 353, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 257 for clarity. Putting them Together: An OOP Example![]() A class called Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 is to be defined as illustrated in the class diagram. It contains two data members: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 (of type 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 357) and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 255 (of type 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 359); and three member functions: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 256, > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red01, and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 257. Three instances of Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9s called 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 259, double radius = 1.0; // error: ISO C++ forbids in-class initialization of non-const static member 'radius'0, and double radius = 1.0; // error: ISO C++ forbids in-class initialization of non-const static member 'radius'1 shall then be constructed with their respective data members, as shown in the instance diagrams. In this example, we shall keep all the codes in a single source file called > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red07. CircleAIO.cpp1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 To compile and run the program (with GNU GCC under Windows): > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red ConstructorsA constructor is a special function that has the function name same as the classname. In the above Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 class, we define a constructor as follows: A constructor is used to construct and initialize all the data members. To create a new instance of a class, you need to declare the name of the instance and invoke the constructor. For example, A constructor function is different from an ordinary function in the following aspects:
Default Arguments for FunctionsIn C++, you can specify the default value for the trailing arguments of a function (including constructor) in the function header. For example, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 "public" vs. "private" Access Control ModifiersAn access control modifier can be used to control the visibility of a data member or a member function within a class. We begin with the following two access control modifiers:
For example, in the above Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 definition, the data member 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 is declared Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2. As the result, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 is accessible inside the Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 class, but NOT outside theclass. In other words, you cannot use " > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red18" to refer to 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 259's 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 in > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red21. Try inserting the statement " > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red22" in > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red21 and observe the error message: CircleAIO.cpp:8:11: error: 'double Circle::radius' is private Try moving 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 to the Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }3 section, and re-run the statement. On the other hand, the function 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 256 is declared Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }3 in the Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 class. Hence, it can be invoked in the > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red21. UML Notation: In UML notation, Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }3 members are denoted with a " > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red31", while Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 members with a " > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red33" in the class diagram. Information Hiding and EncapsulationA class encapsulates the static attributes and the dynamic behaviors into a "3-compartment box". Once a class is defined, you can seal up the "box" and put the "box" on the shelve for others to use and reuse. Anyone can pick up the "box" and use it in their application. This cannot be done in the traditional procedural-oriented language like C, as the static attributes (or variables) are scattered over the entire program and header files. You cannot "cut" out a portion of C program, plug into another program and expect the program to run without extensive changes. Data member of a class are typically hidden from the outside word, with Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 access control modifier. Access to the private data members are provided via Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }3 assessor functions, e.g., 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 256 and > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red01. This follows the principle of information hiding. That is, objects communicate with each others using well-defined interfaces (public functions). Objects are not allowed to know the implementation details of others. The implementation details are hidden or encapsulated within the class. Information hiding facilitates reuse of the class. Rule of Thumb: Do not make any data member Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }3, unless you have a good reason. Getters and SettersTo allow other to read the value of a Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 data member says > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red40, you shall provide a get function (or getter or accessor function) called > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red41. A getter need not expose the data in raw format. It can process the data and limit the view of the data others will see. Getters shall not modify the data member. To allow other classes to modify the value of a Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 data member says > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red40, you shall provide a set function (or setter or mutator function) called > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red44. A setter could provide data validation (such as range checking), and transform the raw data into the internal representation. For example, in our Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 class, the data members 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 255 are declared Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2. That is to say, they are only available within the Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 class and not visible outside the Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 class - including > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red21. You cannot access the Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 data members 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 255 from the > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red21 directly - via says > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red18 or > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red57. The Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 class provides two public accessor functions, namely, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 256 and > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red01. These functions are declared Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }3. The > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red21 can invoke these public accessor functions to retrieve the 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 255 of a Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 object, via says > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red66 and > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red67. There is no way you can change the 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 or 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 255 of a Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 object, after it is constructed in > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red21. You cannot issue statements such as > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red72 to change the 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 of instance 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 259, as 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 is declared as Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 in the Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 class and is not visible to other including > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red21. If the designer of the Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 class permits the change the 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 255 after a Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 object is constructed, he has to provide the appropriate setter, e.g., With proper implementation of information hiding, the designer of a class has full control of what the user of the class can and cannot do. Keyword "this"You can use keyword " > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red83" to refer to this instance inside a class definition. One of the main usage of keyword > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red83 is to resolve ambiguity between the names of data member and function parameter. For example, In the above codes, there are two identifiers called 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 - a data member and the function parameter. This causes naming conflict. To resolve the naming conflict, you could name the function parameter > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red86 instead of 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254. However, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254 is more approximate and meaningful in this context. You can use keyword > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red83 to resolve this naming conflict. " > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red90" refers to the data member; while " 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 254" resolves to the function parameter. " > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red83" is actually a pointer to this object. I will explain pointer and the meaning of " > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red93" operator later. Alternatively, you could use a prefix (such as > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red94) or suffix (such as > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red95) to name the data members to avoid name crashes. For example, C++ Compiler internally names their data members beginning with a leading underscore ( > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red96) and local variables with 2 leading underscores (e.g., > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red97). Hence, avoid name beginning with underscore in your program. "const" Member FunctionsA > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red98 member function, identified by a > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red98 keyword at the end of the member function's header, cannot modifies any data member of this object. For example, Convention for Getters/Setters and ConstructorsThe constructor, getter and setter functions for a Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 data member called > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red40 of type 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2102 in a class 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2103 have the following conventions: For a 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2104 variable > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red40, the getter shall be named 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2106, instead of > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red41, as follows: Default ConstructorA default constructor is a constructor with no parameters, or having default values for all the parameters. For example, the above Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9's constructor can be served as default constructor with all the parameters default. If C++, if you did not provide ANY constructor, the compiler automatically provides a default constructor that does nothing. That is, Compiler will not provide a default constructor if you define any constructor(s). If all the constructors you defined require arguments, invoking no-argument default constructor results in error. This is to allow class designer to make it impossible to create an uninitialized instance, by NOT providing an explicit default constructor. Constructor's Member Initializer ListInstead of initializing the private data members inside the body of the constructor, as follows: Circle(double r = 1.0, string c = "red") { radius = r; color = c; } We can use an alternate syntax called member initializer list as follows: Circle(double r = 1.0, string c = "red") : radius(r), color(c) { } Member initializer list is placed after the constructor's header, separated by a colon ( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2109). Each initializer is in the form of 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2110. For fundamental type, it is equivalent to 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2111. For object, the constructor will be invoked to construct the object. The constructor's body (empty in this case) will be run after the completion of member initializer list. It is recommended to use member initializer list to initialize all the data members, as it is often more efficient than doing assignment inside the constructor's body. *DestructorA destructor, similar to constructor, is a special function that has the same name as the classname, with a prefix 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2112, e.g., 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2113. Destructor is called implicitly when an object is destroyed. If you do not define a destructor, the compiler provides a default, which does nothing. Advanced Notes
*Copy ConstructorA copy constructor constructs a new object by copying an existing object of the same type. In other words, a copy constructor takes an argument, which is an object of the same class. If you do not define a copy constructor, the compiler provides a default which copies all the data members of the given object. For example, The copy constructor is particularly important. When an object is passed into a function by value, the copy constructor will be used to make a clone copy of the argument. Advanced Notes
*Copy Assignment Operator (=)The compiler also provides a default assignment operator ( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2121), which can be used to assign one object to another object of the same class via memberwise copy. For example, using the Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 class defined earlier, Advanced Notes
Separating Header and ImplementationFor better software engineering, it is recommended that the class declaration and implementation be kept in 2 separate files: declaration is a header file " 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2126"; while implementation in a " 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2127". This is known as separating the public interface (header declaration) and the implementation. Interface is defined by the designer, implementation can be supplied by others. While the interface is fixed, different vendors can provide different implementations. Furthermore, only the header files are exposed to the users, the implementation can be provided in an object file " 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2128" (or in a library). The source code needs not given to the users. I shall illustrate with the following examples. Example: The Circle Class![]() Instead of putting all the codes in a single file. We shall "separate the interface and implementation" by placing the codes in 3 files.
Circle.h - Header1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Program Notes:
Header files shall contains constants, function prototypes, class/struct declarations. Circle.cpp - Implementation1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 Program Notes:
Compiling the Circle ClassYou can compile the 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2131 to an object file called 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2142, via option 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2143 (compile-only) in GNU GCC: > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red1 To use the Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 class, the user needs 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2129 and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2142. He does not need 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2131. In other words, you do not need to give away your source codes, but merely the public declarations and the object codes. TestCircle.cpp - Test DriverLet's write a test program to use the Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }9 class created. > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red2 Compiling the Test ProgramTo compile 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2133 with the object code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2142 (and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2129): > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red3 You can also compile 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2133 with the source code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2131 (and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2129) > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red4 ![]() Let's write a class called 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2155, which models a specific instance of time with hour, minute and second values, as shown in the class diagram. The class 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2155 contains the following members:
Let's write the code for the 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2155 class, with the header and implementation separated in two files: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2188 and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2189. Header - Time.h> g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red5 Dissecting Time.h#ifndef TIME_H 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2190), we wrap the header codes within a pair of preprocessor directives 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2191 (if not define) and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2192. The codes within the if-block will only be included if the identifier 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2193 has not been defined. This is true for the first inclusion, which also defines the identifier 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2193 (the first directive in body of the if-block). No subsequent inclusion is possible, since 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2193 has been defined during the first inclusion. By convention, use the identifier 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2196 (or 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2197) for header 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2198. class Time { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2188 contains the class declaration for the class 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2155. It is divided into two sections: Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 and Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }3. The Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 members (data or functions) are accessible by members of this class only, while Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }3 members are visible by all (such as the > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red21 function which is outside the class). The class declaration must be terminated by a semicolon. private: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2158, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2159 and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2160. In C++98/C++03, you are NOT allow to initialize a data member in the class declaration (except > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red98 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2136 CircleAIO.cpp:8:11: error: 'double Circle::radius' is private11 data members). For example, setting CircleAIO.cpp:8:11: error: 'double Circle::radius' is private12 causes a compilation error. Instead, the data members are to be initialized in the constructor (to be shown later). The newer C++11 allows initialization of data members. Only member function prototypes are listed in the class declaration. A function prototype consists of the return-type, function name and parameter types. Time(int h = 0, int m = 0, int s = 0); > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red09. No > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red10 statement is allowed inside the constructor's body. A constructor can only be used during the instance declaration to initialize the data members of the instance. It cannot be invoked thereafter. In the function prototypes of the header, we can set the default values of the function's parameters for any function member using " CircleAIO.cpp:8:11: error: 'double Circle::radius' is private15". In this case, this constructor can be invoked with 0 to 3 arguments, the omitted trailing arguments will be set to their default values, e.g., The identifiers CircleAIO.cpp:8:11: error: 'double Circle::radius' is private16, CircleAIO.cpp:8:11: error: 'double Circle::radius' is private17 and CircleAIO.cpp:8:11: error: 'double Circle::radius' is private18 are not needed in the function prototype - you only need to specify the parameters' types. But they serve as proper documentation, and are strongly recommended. int getHour() const; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2158, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2159 and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2160. Since the data members are Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 and are not accessible outside the class, Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }3 getters and setters are often provided to read and modify the Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 data members. By convention, a getter receives nothing ( > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red09) from the caller and returns a value of the type of the data member; a setter receives a value of the type of the data member and returns > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red09. Setters may validate the input before setting the value of the data member. We declare the getter function constant, by placing the keyword > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red98 after the function parameter list. A > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red98 member function cannot modify any data member of this object. Getter does not need to modify any data member. void setTime(int h, int m, int s); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2158, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2159 and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2160 of this instance in one call. void print() const; CircleAIO.cpp:8:11: error: 'double Circle::radius' is private32, zero-filled, e.g., CircleAIO.cpp:8:11: error: 'double Circle::radius' is private33. The function 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2178 returns > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red09. void nextSecond(); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2185 becomes 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2186. The function 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2183 returns > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red09. Implementation - Time.cpp> g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red6 Dissecting Time.cppThe implementation file 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2189 contains member's definitions (whereas the header file contains the declarations), in particular, member functions. All member's identifiers in the implementation are preceded by the classname and the scope resolution operator ( CircleAIO.cpp:8:11: error: 'double Circle::radius' is private41), e.g., CircleAIO.cpp:8:11: error: 'double Circle::radius' is private42 and CircleAIO.cpp:8:11: error: 'double Circle::radius' is private43, so that the compiler can tell that these identifiers belong to a particular class, in this case, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2155. Time::Time(int h, int m, int s) { Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 data members 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2158, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2159 and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2160 based on the inputs provided by the caller. C++ does NOT initialize fundamental-type (e.g., CircleAIO.cpp:8:11: error: 'double Circle::radius' is private11, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 357) data members. It also does NOT issue an error message if you use an data member before it is initialized. Hence, It is strongly recommended to initialize all the data members in the constructor, so that the constructed instance is complete, instead of relying on the user to set the values of the data members after construction. The default values of the parameters are specified in the class declaration (in the header), NOT in the function definition. Placing a default value in function definition (e.g., CircleAIO.cpp:8:11: error: 'double Circle::radius' is private51) causes a compilation error. Take note that we have not included input validation (e.g., hour shall be between 0 and 23) in the constructor (and setters). We shall do that in the later example. int Time::getHour() const { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2158 simply returns the value of the data member 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2158. void Time::setHour(int h) { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2158 sets the data member 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2158 to the given value CircleAIO.cpp:8:11: error: 'double Circle::radius' is private16. Again, there is no input validation for h (shall be between 0 to 23). The rest of the function definitions are self-explanatory. "this" PointerInstead of naming the function parameters CircleAIO.cpp:8:11: error: 'double Circle::radius' is private16, CircleAIO.cpp:8:11: error: 'double Circle::radius' is private17 and CircleAIO.cpp:8:11: error: 'double Circle::radius' is private18, we would like to name the parameters 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2158, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2159 and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2160, which are semantically more meaningful. However, these names crashes with the names of private data members. C++ provides a keyword > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red83 (which is a pointer to this instance - to be discussed later) to differentiate between the data members and function parameters. CircleAIO.cpp:8:11: error: 'double Circle::radius' is private64, CircleAIO.cpp:8:11: error: 'double Circle::radius' is private65 and CircleAIO.cpp:8:11: error: 'double Circle::radius' is private66 refer to the data members; while 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2158, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2159, and 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2160 refer to the function parameters. We can rewrite the constructor and setter as follows: Member Initializer ListC++ provide an alternative syntax to initialize data members in the constructor called member initializer list. For example, The member initializer list is placed after the function parameter list, separated by a colon, in the form of CircleAIO.cpp:8:11: error: 'double Circle::radius' is private70. For fundamental-type data members (e.g., CircleAIO.cpp:8:11: error: 'double Circle::radius' is private11, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 357), CircleAIO.cpp:8:11: error: 'double Circle::radius' is private73 is the same as CircleAIO.cpp:8:11: error: 'double Circle::radius' is private74. For object data members (to be discussed later), the copy constructor will be invoked. The function body will be executed after the member initializer list, which is empty in this case. The data members in the initializer list are initialized in the order of their declarations in the class declaration, not the order in the initializer list. Test Driver - TestTime.cpp> g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red7 Dissecting TestTime.cppThe test driver tests the constructor (with and without the default values) and all the public member functions. Clearly, no input validation is carried out, as reflected in instance CircleAIO.cpp:8:11: error: 'double Circle::radius' is private75. ExerciseAdd member functions CircleAIO.cpp:8:11: error: 'double Circle::radius' is private76, CircleAIO.cpp:8:11: error: 'double Circle::radius' is private77, CircleAIO.cpp:8:11: error: 'double Circle::radius' is private78, CircleAIO.cpp:8:11: error: 'double Circle::radius' is private79, CircleAIO.cpp:8:11: error: 'double Circle::radius' is private80 to the 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2155 class. Compiling the ProgramYou can compile all the source file together to get the executable file as follows: > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red8 Alternatively, you can compile 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2189 into an object file CircleAIO.cpp:8:11: error: 'double Circle::radius' is private83, and then the test driver with the object file. In this way, you only distribute the object file and header file, not the source file. > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red9 Example: The Point Class![]() The CircleAIO.cpp:8:11: error: 'double Circle::radius' is private84 class, as shown in the class diagram, models 2D points with x and y co-ordinates. In the class diagram, " > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red33" denotes Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 member; " > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red31" denotes Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }3 member. " CircleAIO.cpp:8:11: error: 'double Circle::radius' is private89" specifies the default value of a data member. The CircleAIO.cpp:8:11: error: 'double Circle::radius' is private84 class contains the followings:
Point.h - Header1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Point.cpp - Implementation1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 211 TestPoint.cpp - Test Driver1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Example: The Account Class![]() A class called Circle(double r = 1.0, string c = "red") { radius = r; color = c; }09, which models a bank account, is designed as shown in the class diagram. It contains:
Header file - Account.h1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 213 Implementation file - Account.cpp1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 214 Test Driver - TestAccount.cpp1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Example: The Ball class![]() A Circle(double r = 1.0, string c = "red") { radius = r; color = c; }0 class models a moving ball, designed as shown in the class diagram, contains the following members:
Header File - Ball.h1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 216 Implementation File - Ball.cpp1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 217 Test Driver - TestBall.cpp1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 218 Let's start with the Author class![]() Let's begin with a class called Circle(double r = 1.0, string c = "red") { radius = r; color = c; }36, designed as shown in the class diagram. It contains:
Header File - Author.h1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 219 Implementation File - Author.cppCircleAIO.cpp:8:11: error: 'double Circle::radius' is private0 Dissecting the Author.cppAuthor::Author(string name, string email, char gender) { Circle(double r = 1.0, string c = "red") { radius = r; color = c; }38 in the function's parameter, which crashes with the data member's identifier Circle(double r = 1.0, string c = "red") { radius = r; color = c; }38. To differentiate between the two identifiers, we use the keyword > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red83, which is a pointer to this instance. Circle(double r = 1.0, string c = "red") { radius = r; color = c; }60 refers to the data member; while Circle(double r = 1.0, string c = "red") { radius = r; color = c; }38 refers to the function's parameter. No input validation is done on the parameter Circle(double r = 1.0, string c = "red") { radius = r; color = c; }38. On the other hand, for Circle(double r = 1.0, string c = "red") { radius = r; color = c; }40, we invoke setter Circle(double r = 1.0, string c = "red") { radius = r; color = c; }64 which performs input validation. if (gender == 'm' || gender == 'f') { Circle(double r = 1.0, string c = "red") { radius = r; color = c; }42 ( Circle(double r = 1.0, string c = "red") { radius = r; color = c; }44, Circle(double r = 1.0, string c = "red") { radius = r; color = c; }45, or Circle(double r = 1.0, string c = "red") { radius = r; color = c; }46 for unknown). We assign Circle(double r = 1.0, string c = "red") { radius = r; color = c; }46 for any other inputs. void Author::setEmail(string email) { Circle(double r = 1.0, string c = "red") { radius = r; color = c; }40, we assume that there is an Circle(double r = 1.0, string c = "red") { radius = r; color = c; }71 which is not the first or last character (there are other stricter email validation criteria). We use the Circle(double r = 1.0, string c = "red") { radius = r; color = c; }39 class function Circle(double r = 1.0, string c = "red") { radius = r; color = c; }73 to find the position of the character Circle(double r = 1.0, string c = "red") { radius = r; color = c; }71, which returns a value of type Circle(double r = 1.0, string c = "red") { radius = r; color = c; }75 (typically same as Circle(double r = 1.0, string c = "red") { radius = r; color = c; }76). The function Circle(double r = 1.0, string c = "red") { radius = r; color = c; }73 returns a special constant Circle(double r = 1.0, string c = "red") { radius = r; color = c; }78 (which is typically set to -1) to indicate "not found"; 0 for the first character and Circle(double r = 1.0, string c = "red") { radius = r; color = c; }79 for the last character (where Circle(double r = 1.0, string c = "red") { radius = r; color = c; }39's function Circle(double r = 1.0, string c = "red") { radius = r; color = c; }81 returns the length of the string). TestAuthor.cpp1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 213 A Book is written by an Author - Using an "Object" Data Member![]() Let's design a Circle(double r = 1.0, string c = "red") { radius = r; color = c; }82 class. Assume that a book is written by one and only one author. The Circle(double r = 1.0, string c = "red") { radius = r; color = c; }82 class (as shown in the class diagram) contains the following members:
The hallow diamond shape in the class diagram denotes aggregation (or has-a) association relationship. That is, a Circle(double r = 1.0, string c = "red") { radius = r; color = c; }82 instance has one (and only one) Circle(double r = 1.0, string c = "red") { radius = r; color = c; }36 instance as its component. Header File - Book.hCircleAIO.cpp:8:11: error: 'double Circle::radius' is private2 #include "Author.h" Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }13" header, as we use the Circle(double r = 1.0, string c = "red") { radius = r; color = c; }36 class in this class Circle(double r = 1.0, string c = "red") { radius = r; color = c; }82. private: Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }2 data member Circle(double r = 1.0, string c = "red") { radius = r; color = c; }87 as an instance of class Circle(double r = 1.0, string c = "red") { radius = r; color = c; }36, defined earlier. Implementation File - Book.cpp1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 217 Book::Book(string name, Author author, double price, int qtyInStock) Circle(double r = 1.0, string c = "red") { radius = r; color = c; }36, and pass the instance into the constructor. We use member initializer list to initialize data members Circle(double r = 1.0, string c = "red") { radius = r; color = c; }38 and Circle(double r = 1.0, string c = "red") { radius = r; color = c; }87. We call setters in the body, which perform input validation to set the Circle(double r = 1.0, string c = "red") { radius = r; color = c; }89 and Circle(double r = 1.0, string c = "red") { radius = r; color = c; }91. The body is run after the member initializer list. The Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }24 invokes the default copy constructor of the Circle(double r = 1.0, string c = "red") { radius = r; color = c; }36 class, which performs memberwise copy for all the data members. Object data member shall be constructed via the member initializer list, not in the body. Otherwise, the default constructor will be invoked to construct the object. void Book::setPrice(double price) { Circle(double r = 1.0, string c = "red") { radius = r; color = c; }89 validates the given input. string Book::getAuthorName() const { Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }27 of the data member Circle(double r = 1.0, string c = "red") { radius = r; color = c; }87, which returns the author's name of this Circle(double r = 1.0, string c = "red") { radius = r; color = c; }82 instance. TestBook.cpp> g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red5 The Default Copy ConstructorThe initializer Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }24 in the constructor invokes the so-called copy constructor. A copy constructor creates a new instance by copying the given instance of the same class. If you do not provide a copy constructor in your class, C++ provides a default copy constructor, which construct a new object via memberwise copy. For example, for Circle(double r = 1.0, string c = "red") { radius = r; color = c; }36 class, the default copy constructor provided by the compiler is as follows: Pass-by-Reference for Objects Function Parameters Author and stringBy default, objects are pass-by-value into functions. That is, a clone copy is created and pass into the function, instead of the original copy. Pass-by-value for huge objects depicts performance due to the overhead of creating a clone copy. Instead, we could pass an object into function by reference, via the reference ( Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }32) declaration in the parameter list. If we do not intend to modify the object inside the function (with side effect to the original copy), we set it as > g++ -o CircleAIO.exe CircleAIO.cpp // -o specifies the output file name > CircleAIO Radius=1.2 Area=4.5239 Color=blue Radius=3.4 Area=36.3169 Color=red Radius=1 Area=3.1416 Color=red98. In the Circle(double r = 1.0, string c = "red") { radius = r; color = c; }82 class, data members of Circle(double r = 1.0, string c = "red") { radius = r; color = c; }39 and Circle(double r = 1.0, string c = "red") { radius = r; color = c; }36 are objects. Circle(double r = 1.0, string c = "red") { radius = r; color = c; }36 class was defined earlier; Circle(double r = 1.0, string c = "red") { radius = r; color = c; }39 is a class provided in C++ header 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2138, belonging to the namespace Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }40. Instead of including " Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }41" in the header (which is a poor practice as this statement will be included in all the files using this header), we shall use the scope resolution operator and refer to it as Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }42. Let's modify our Circle(double r = 1.0, string c = "red") { radius = r; color = c; }82 class to illustrate pass-by-reference (for performance). Author.h1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 219 Program Notes:
Author.cppCircleAIO.cpp:8:11: error: 'double Circle::radius' is private6 Program Notes:
Book.hCircleAIO.cpp:8:11: error: 'double Circle::radius' is private7 Program Notes:
Book.cpp1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 217
Test Driver - TestBook.cppCircleAIO.cpp:8:11: error: 'double Circle::radius' is private9 In the above test program, an instance of Circle(double r = 1.0, string c = "red") { radius = r; color = c; }36 called Circle(double r = 1.0, string c = "red") { radius = r; color = c; }9 is constructed (in Line 8). This instance is passed by reference into Circle(double r = 1.0, string c = "red") { radius = r; color = c; }82's constructor (Line 12) to create the Circle(double r = 1.0, string c = "red") { radius = r; color = c; }82's instance Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }73. SummaryAll the codes in this version of example (using references) is exactly the same as the previous version (without using references), except that the object function parameters are marked with " Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }74" (e.g., Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }75, Circle(double r = 1.0, string c = "red") : radius(r), color(c) { }76). This eliminates the creation of temporary clone object as in the pass-by-value, which improves the performance. Take note that the constructor actually invokes the copy constructor to make a copy for its data member, instead of referencing the copy provided by the caller. |
Bài Viết Liên Quan
How to clean Disk C Windows 10
No matter how large a hard drive or solid-state drive you have in your PC or laptop, there will come a time when you run out of space. If youre bumping up against your PCs physical storage limit, ...
Có nên uống vitamin c của amway
Thiếu vitamin C nghiêm trọng có thể dẫn đến một bệnh đặc trưng là thiếu máu, nướu dễ bị chảy máu, bầm tím và lâu lành vết thương. Đặc biệt ở ...
Debug c++ in cmd windows 10
Ive never used a debugger and the time has come to give them a try. MinGW appears to come with GDB which Ive been trying to use. Supposdly running gdb from the command line and typing run ...
Cách chạy chương trình dev c++
Với người mới bắt đầu học lập trình, ngôn ngữ được ưu tiên hàng đầu và gần như bắt buộc đó chính là C/C++. Tuy nhiên, có nhiều IDE hỗ trợ cho ngôn ...
Which kind of error occurs when a program does not perform the intended task
Errors in C/C++Improve Article Save Article Like Article Difficulty Level : EasyLast Updated : 09 Jun, 2022ReadDiscuss(9)CoursesPracticeVideoImprove Article Save Article Error is an illegal operation ...
Từ có 5 chữ cái với c là chữ cái đầu tiên năm 2022
Trước khi mắt đầu học một ngôn ngữ tiếng Anh thì việc học thuộc bảng chữ cái tiếng Anh và cách phát âm là khởi đầu quan trọng cho một nền ...
Dependency la gì
Dependency Injection đối với 1 số bạn vẫn là 1 khái niệm khá mơ hồ. Nếu bạn cũng nằm trong số người mơ hồ đấy hãy theo dõi bài viết này nhéDependency ...
Which keyword can be used in subclass to call the constructor of superclass?
Subclasses inherit public methods from the superclass that they extend, but they cannot access the private instance variables of the superclass directly and must use the public accessor and mutator ...
What is a function with the same name as another function in its class called?
Generally speaking, a function is a subprogram that can be called by code external (or internal in the case of recursion) to the function. Like the program itself, a function is composed of a ...
Top 20 cửa hàng c mart Thị xã Dĩ An Bình Dương 2022
Bài viết đánh giá Top 20 cửa hàng c mart Thị xã Dĩ An Bình Dương 2022 theo quan điểm cá nhân của tác giả Go! Dĩ An 8224 đánh ...