Object-Oriented Programming (OOP) in C++
- Object-Oriented Programming (OOP) in C++
- 1. Why OOP?
- 2. OOP Basics
- 2.1 Classes & Instances
- 2.2 A Class is a 3-Compartment Box encapsulating Data and Functions
- 2.3 Class Definition
- 2.4 Creating Instances of a Class
- 2.5 Dot (.) Operator
- 2.10 Default Arguments for Functions
- 2.13 Getters and Setters
- 2.14 Keyword "this"
- 2.16 Convention for Getters/Setters and Constructors
- 2.17 Default Constructor
- 2.18 Constructor's Member Initializer List
- 2.19 *Destructor
- 2.20 *Copy constructor and assignment
- 3. Separating Header and Implementation
1. Why OOP?
1.1 Traditional Procedural-Oriented languages
Traditional procedural-oriented languages (such as C and Pascal) suffer some notable drawbacks in creating reusable software components:
-
The programs are made up of functions. Functions are often not reusable.
- It is very difficult to copy a function from one program and reuse in another program because the the function is likely to reference the headers, global variables and other functions.
-
The procedural languages are not suitable of high-level abstraction for solving real life problems.
- Imagine using assembly codes, which is a very low level code, to write a computer soccer game. C is better but no much better.
In brief, the traditional procedural-languages separate the data structures and algorithms of the software entities.
1.2 Object-Oriented Programming Languages
The basic unit of OOP is a class, which encapsulates both the static attributes and dynamic behaviors within a "box", and specifies the public interface for using these boxes. In other words, OOP combines the data structures and algorithms of a software entity inside the same box.
OOP languages permit higher level of abstraction for solving real-life problems.
The traditional procedural language forces you to think in terms of the structure of the computer (e.g. memory bits and bytes, array, decision, loop) rather than thinking in terms of the problem you are trying to solve.
The OOP languages (such as Java, C++, C#) let you think in the problem space, and use software objects to represent and abstract entities of the problem space to solve the problem.
2. OOP Basics
2.1 Classes & Instances
Class: 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.
All the instances of a class have similar properties, as described in the class definition. For example, you can define a class called "Student
" and create three instances of the class "Student
" for "Peter
", "Paul
" and "Pauline
".
The term "object" usually refers to instance.
But it is often used quite loosely, which may refer to a class or an instance.
2.2 A Class is a 3-Compartment Box encapsulating Data and Functions
A class can be visualized as a three-compartment box, as illustrated:
- Classname (or identifier): identifies the class.
- Data Members or Variables (or attributes, states, fields)
- Member Functions (or methods, behaviors, operations)
In other words, a class encapsulates the static attributes (data) and dynamic behaviors (operations that operate on the data) in a box.
The data members and member functions are collectively called class members.
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.
2.3 Class Definition
In C++, we use the keyword class
to define a class.
There are two sections in the class declaration: private
and public
.
class SoccerPlayer { // classname
private:
int number; // Data members (variables)
string name;
int x, y;
public:
void run(); // Member functions
void kickBall();
}
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,
SoccerPlayer
,HttpProxyServer
,FileInputStream
,PrintStream
andSocketFactory
.
2.4 Creating Instances of a Class
To create an instance of a class, you have to:
- Declare an instance identifier (name) of a particular class.
- Invoke(调用) a constructor to construct the instance (i.e., allocate storage for the instance and initialize the variables).
2.5 Dot (.) Operator
To reference a member of a object (data member or member function), you must:
// Declare and construct instances c1 and c2 of the class Circle
Circle c1(1.2, "blue");
Circle c2(3.4, "green");
// Invoke member function via dot operator
cout << c1.getArea() << endl;
cout << c2.getArea() << endl;
// Reference data members via dot operator
c1.radius = 5.5;
c2.radius = 6.6;
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,
getRadius()
,getParameterValues()
.
class Circle {
private:
double radius; // Data member (Variable)
string color; // Data member (Variable)
public:
// Constructor with default values for data members
Circle(double r = 1.0, string c = "red") {
radius = r;
color = c;
}
}; // need to end the class declaration with a semi-colon
int main() {
// Construct a Circle instance
Circle c1(1.2, "blue");
cout << "Radius=" << c1.getRadius() << " Area=" << c1.getArea()
<< " Color=" << c1.getColor() << endl;
}
A constructor is a special function that has the function name same as the classname.
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,
Circle c1(1.2, "blue");
Circle c2(3.4); // default color
Circle c3; // default radius and color
// Take note that there is no empty bracket ()
- The name of the constructor is the same as the classname.
- Constructor has no return type (or implicitly returns
void
). Hence, noreturn
statement is allowed inside the constructor's body. - Constructor can only be invoked once to initialize the instance constructed. You cannot call the constructor afterwards in your program.
- Constructors are not inherited
2.10 Default Arguments for Functions
In C++, you can specify the default value for the trailing arguments of a function (including constructor) in the function header. For example,
// Function prototype
int sum(int n1, int n2, int n3 = 0, int n4 = 0, int n5 = 0);
int main() {
cout << sum(1, 1, 1, 1, 1) << endl; // 5
cout << sum(1, 1, 1, 1) << endl; // 4
cout << sum(1, 1, 1) << endl; // 3
cout << sum(1, 1) << endl; // 2
// cout << sum(1) << endl; // error: too few arguments
}
// The default values shall be specified in function prototype,
// not the function implementation
int sum(int n1, int n2, int n3, int n4, int n5) {
return n1 + n2 + n3 + n4 + n5;
}
UML Notation: In UML notation, public
members are denoted with a "+
", while private
members with a "-
" in the class diagram.
Rule of Thumb: Do not make any data member public
, unless you have a good reason.
2.13 Getters and Setters
To allow other to read the value of a private
data member says xxx
, you shall provide a get function (or getter or accessor function) called getXxx()
.
- 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 private
data member says xxx
, you shall provide a set function (or setter or mutator function) called setXxx()
.
- A setter could provide data validation (such as range checking), and transform the raw data into the internal representation.
2.14 Keyword "this"
You can use keyword "this
" to refer to this instance inside a class definition.
One of the main usage of keyword this
is to resolve ambiguity between the names of data member and function parameter.
class Circle {
private:
double radius; // Member variable called "radius"
......
public:
void setRadius(double radius) { // Function's argument also called "radius"
this->radius = radius;
// "this.radius" refers to this instance's member variable
// "radius" resolved to the function's argument.
}
......
}
"this
" is actually a pointer to this object.
you could use a prefix (such as m_
) or suffix (such as _
) to name the data members to avoid name crashes, like radius_
, f_radius
.
_xxx
C++ Compiler internally names their data members beginning with a leading underscore (e.g., _xxx
) and local variables with 2 leading underscores (e.g., __xxx
).
Hence, avoid name beginning with underscore in your program.
顺便了解的
html里面tab的实体名称是 &emsp 来源是字体排印学计量单位 Em Space,意指当前指定的点数
而空格   的全称是 non-breaking space,意指不在此处换行。
当页面变窄之后,文字会在空格处折行,但是插入 的空格则不会折行继续以一行显示
还有一个小quiz,请分辨一下三种类型
const *string p
string *const p
string const *p
2.16 Convention for Getters/Setters and Constructors
有点混乱
class C {
private:
// A private variable named V of type T
T V;
public:
// Constructor
C(T x) { V = x; }
// OR
C(T V) { this->V = V; }
// OR using member initializer list (to be explained later)
C(T V) : V(V) { }
// A getter for variable V of type T receives no argument and return a value of type T
T getV() const { return V; }
// A setter for variable V of type T receives a parameter of type T and return void
void setV(T x) { V = x; }
// OR
void setV(T V) { this->V = V; }
}
For a bool
variable xxx
, the getter shall be named isXxx()
, instead of getXxx()
, as follows:
private:
// Private boolean variable
bool xxx;
public:
// Getter
bool isXxx() const { return xxx; }
// Setter
void setXxx(bool x) { xxx = x; }
// OR
void setXxx(bool xxx) { this->xxx = xxx; }
2.17 Default Constructor
A default constructor is a constructor with no parameters, or having default values for all the parameters.
Circle c1; // Declare c1 as an instance of Circle, and invoke the default constructor
Circle c1(); // Error!
// (This declares c1 as a function that takes no parameter and returns a Circle instance)
If C++, if you did not provide ANY constructor, the compiler automatically provides a default constructor that does nothing. That is,
2.18 Constructor's Member Initializer List
Instead of initializing the private data members inside the body of the constructor, as follows:
We can use an alternate syntax called member initializer list as follows:
Member initializer list is placed after the constructor's header, separated by a colon (:
).
For fundamental type, it is equivalent to *data_member_name* = *parameter_name*
.
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.
2.19 *Destructor
A destructor, similar to constructor, is a special function that has the same name as the classname, with a prefix ~
, e.g., ~Circle()
.
Destructor is called implicitly when an object is destroyed. Namely, the destructor is called whenever an object's lifetime ends.
如在程序结束时执行,此时没被释放的对象会被自动释放x
改:不管你有没有使用,g++都会执行你定义的~circle,导致里面的语句被重复执行
If you do not define a destructor, the compiler provides a default, which does nothing.
The destructor may also be called directly, e.g. to destroy an object
Advanced Notes
- If your class contains data member which is dynamically allocated (via
new
ornew[]
operator), you need to free the storage viadelete
ordelete[]
.
2.20 *Copy constructor and assignment
A 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.
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.
- You could overload the assignment opeator to override the default.
- The copy constructor, instead of copy assignment operator, is used in declaration:
- The default copy assignment operator performs shadow copy. It does not copy the dynamically allocated data members created via
new
ornew[]
operator. - The default constructor, default destructor, default copy constructor, default copy assignment operators are known as special member functions, in which the compiler will automatically generate a copy if they are used in the program and not explicitly defined.
3. Separating Header and Implementation
For better software engineering, it is recommended that the class declaration and implementation be kept in 2 separate files: declaration is a header file ".h
"; while implementation in a ".cpp
".
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 ".o
" (or in a library).
The source code needs not given to the users.
除了头文件,class的定义也可以放在
.h
-
C++98/03 does NOT allow you to assign an initial value to a data member (except
const static
members). Date members are to be initialized via the constructor. For example,double radius = 1.0; // error: ISO C++ forbids in-class initialization of non-const static member 'radius'
C++11 allows in-class initialization of data members.
-
You can provide default value to function's arguments in the header. For example,
-
Header contains function prototype, the parameter names are ignored by the compiler, but good to serve as documentation. For example, you can leave out the parameter names in the prototype as follows:
Header files shall contains constants, function prototypes, class/struct declarations.
- The compiler searches the headers in double quotes (such as
"Circle.h"
) in the current directory first, then the system's include directories.- For header in angle bracket (such as
<iostream>
), the compiler does NOT searches the current directory, but only the system's include directories.
- For header in angle bracket (such as