Article Directory
- 1. From process-oriented to object-oriented
- 2. The introduction of the class
- 3. Class definition
- 4. Class access qualifier and encapsulation
- Five. The scope of the class
- Six. Class instantiation
- Seven. Class object model
- Eight. this pointer
- Nine. Comparison of C language and C++ implementation stack
foreword
This chapter will officially start
C++
a series of explanations, and this article will give a preliminary understanding of classes and objects
1. From process-oriented to object-oriented
C语言
It is process-oriented, focusing on the process , analyzing the steps to solve the problem , and solving the problem step by step through function callsC++
It is based on object-oriented, focusing on objects , splitting one thing into different objects , and relying on the interaction between objects to complete.
For example: To do the laundry
C语言
:
C++
:
- Four objects: people, clothes, washing powder, washing machine
- The process of washing clothes: the person puts the clothes into the washing machine, pours the washing powder, starts the washing machine, the washing machine will wash the clothes and spin dry
- The whole process is completed by the interaction between the four objects of people, clothes, washing powder, and washing machine . People don't need to care about how the washing machine washes clothes and how it dries them.
2. The introduction of the class
C语言
In , only variables can be defined in the structure . In , not only variables can be definedC++
in the structure , but also functions can be defined .
When we used to implement the data structure - stack in the past C语言
, we defined it like this:
//C语言
typedef int dataOfStackType;
typedef struct stack
{
dataOfStackType* a;
int top;
int capacity;
}stack;
void StackInit(stack* ps);
void StackPush(stack* ps, dataOfStackType data);
void StackPop(stack* ps);
//...
Whereas in C++
, we can define it like this:
//C++
typedef int dataOfStackType;
typedef struct stack
{
void StackInit(stack* ps);
void StackPush(stack* ps, dataOfStackType data);
void StackPop(stack* ps);
//...
dataOfStackType* a;
int top;
int capacity;
}stack;
Like the definition above, C++中
prefer to use a new name - class
instead struct
:
class stack
{
void StackInit(stack* ps);
void StackPush(stack* ps, dataOfStackType data);
void StackPop(stack* ps);
//...
dataOfStackType* a;
int top;
int capacity;
};
3. Class definition
1. What is a class
class className
{
//...类的主体:由成员函数和成员变量组成
}; // 一定要注意后面的分号
As shown above, the definition of a class is very similar to the definition of a struct:
class
: A keyword that defines a classclass Name
: the name of the class- The main body of the class:
{}
the middle is the main body of the class, which consists of member variables and member functions - Member variable: also known as the attribute of the class, refers to the variable defined in the class
- Member function: also known as class method, refers to the function defined in the class
2. Class definition
There are generally two ways to define a class:
- The declaration and definition are all placed in the class body. Note: If the member function is defined in the class, the compiler may treat it as an inline function .
//日期类
class Date
{
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
int _year;
int _month;
int _day;
};
- The class declaration is placed in the .h file , and the member function definition is placed in the .cpp file. Note: the class name needs to be added before the member function name
::
.
//Date.h文件中声明类
//日期类
class Date
{
public:
void Init(int year, int month, int day);
void Print();
int _year;
int _month;
int _day;
};
//Date.c文件中定义成员函数
#include"Date.h"
void Date::Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Date::Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
In general, the second approach is more desirable.
3. Suggestions for member variable naming rules
Let's look at the following class:
class Date
{
public:
void Init(int year)
{
//这里的year到底是成员变量,还是函数形参?
year = year;
}
private:
int year;
};
Are the variables above awkward? Are they member variables or function parameters? In order to avoid confusion, we recommend naming member variables as follows Init函数
:year
class Date
{
public:
void Init(int year)
{
_year = year;
}
private:
int _year;
};
// 或者这样
class Date
{
public:
void Init(int year)
{
mYear = year;
}
private:
int mYear;
};
Other methods are also possible, depending on the company's requirements. Generally, it is enough to add a prefix or suffix to identify the difference.
4. Class access qualifier and encapsulation
1. Access qualifiers
We define various member functions and member variables in the class. Sometimes, we don't want others to access some members of the class casually, such as member variables, but other members are open to the outside world, such as member functions. Then we need to use access qualifiers to modify these members .
There are three access qualifiers: public
, protected
,private
Access qualifier description :
class
The default access permissions areprivate
,struct
forpublic
(because ofstruct
compatibilityC
)public
Modified members can be directly accessed outside the classprotected
and modified members cannot be directly accessedprivate
outside the class (here and are similar)protected
private
- Access scopes start at the occurrence of this access qualifier until the next occurrence of the access qualifier
- If there is no access qualifier behind, the scope ends at the
}
end of the class
Note: Access qualifiers are only useful at compile time , when the data is mapped to memory, there is no difference in access qualifiers.
So the question is: what is the difference between c++
neutralization struct
and neutralization?class
Answer:
C++
It needs to be compatibleC语言
, so notC++
onlystruct
can it be used as a structure ,C++
butstruct
it can also be used to define a class , whichclass
is the same as defining a class. The difference is that the default access permissionstruct
of the defined class is , and the default access permission of the defined class is .public
class
private
2. Encapsulation
Object-oriented has three characteristics: encapsulation, inheritance, and polymorphism.
At the current stage, we only learn the features of the package. So what is encapsulation?
Encapsulation: Organically combine data and methods of manipulating data , hide object properties and implementation details, and only expose interfaces to interact with objects
Encapsulation is essentially a kind of management, making it easier for users to use classes :
- For example: for such a complex device as a computer, the only thing provided to the user is the power button, keyboard input, monitor,
USB
jack, etc., allowing the user to interact with the computer and complete daily affairs. But in fact, the real work of the computer is some hardware components such as CPU, graphics card, and memory. - For computer users, they don’t need to care about internal core components , such as how the circuits on the motherboard are laid out, how the CPU is designed inside, etc. Users only need to know how to turn on the computer and how to interact with the computer through the keyboard and mouse . Therefore, when the computer manufacturer leaves the factory, it puts a shell on the outside to hide the internal implementation details, and only provides external switches, mouse and keyboard jacks, etc., so that users can interact with the computer .
- Encapsulation in
C++
the language can organically combine data and methods of manipulating data through classes, hide the internal implementation details of objects through access rights, and control which methods can be used directly outside the class .
Five. The scope of the class
A class defines a new scope , and all members of the class are in the scope of the class. When defining members outside the class, you need to use ::
the scope operator to indicate which class domain the member belongs to :
class Person
{
public:
void PrintPersonInfo();
private:
char _name[20];
char _gender[3];
int _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
cout << _name << " "<< _gender << " " << _age << endl;
}
Six. Class instantiation
The process of creating an object with a class is called instantiation of the class:
//类的声明
class Date
{
public:
//...
int _year;
int _month;
int _day;
};
int main()
{
//类的实例化对象
Date d1;
Date d2;
Date d3;
return 0;
}
Class instantiation of objects is like building a house using design drawings in reality . Classes are like design drawings . Only what is needed is designed, but there is no physical building. The instantiated object is the real house that can actually store data and occupy physical space.
Like a design drawing, it is not that a design drawing can only build one house, and a class can also instantiate multiple objects.
Seven. Class object model
A class can have both member variables and member functions, so how to calculate the size of a class object?
As mentioned above, C++
classes and structures are essentially the same. In order to be compatible C语言
, the calculation rules of the size of the structureC++
will be followed , and the class is the same as the structure, so the class will continue to use the same calculation rules as the structure .
Note: Member functions are in the public code segment , so member functions do not occupy space . Therefore, the size of a class is actually the size of the member variables in the class, following the rules of memory alignment.
Let's verify it:
// 类中既有成员变量,又有成员函数
class A1 {
public:
void f1() {
}
private:
int _a;
char _b;
};
// 类中仅有成员函数
class A2 {
public:
void f2() {
}
};
// 类中什么都没有---空类
class A3
{
};
int main()
{
cout << sizeof(A1) << endl;
cout << sizeof(A2) << endl;
cout << sizeof(A3) << endl;
return 0;
}
operation result:
As shown in the figure above, the result is consistent with the conclusion: the size of the class only calculates the size of the member variables in the class, and follows the memory alignment rules .
- So why is the size of the empty class
1
?
This is because the empty class is special, and the compiler gives the empty class a byte to uniquely identify objects of this class .
Supplement: Structure memory alignment rules :
- The first member is at the address of the structure at offset .
0
- Other member variables should be aligned to an address that is an integer multiple of a certain number (alignment number) . Note: Alignment = the smaller value between the compiler's default alignment and the member size . The default alignment number in VS is 8
- The total size of the structure is: an integer multiple of the maximum alignment number (the largest of all variable types and the smallest default alignment parameter) .
- If a structure is nested, the nested structure is aligned to an integer multiple of its own maximum alignment , and the overall size of the structure is an integer multiple of all maximum alignments (including the alignment of the nested structure) .
Eight. this pointer
1. Know the this pointer
Let's define a date class first Date
:
//日期类
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1, d2;
d1.Init(2022, 1, 11);
d2.Init(2022, 1, 12);
d1.Print();
d2.Print();
return 0;
}
For the above operation, there is such a question:
Date
There are two member functionsInit
and in the class , and there is no distinction between different objects in the function body , so when the function is called , how does the function know that the object should be set instead of the object?Print
d1
Init
d1
d2
C++
this指针
Solve this problem by introducing :
C++
The compiler adds a hidden pointer parameter to each non-static member function , making the pointer point to the current object (the object that calls the function when the function is running), and all member variable operations in the function body are accessed through this pointer . It's just that all operations are transparent to the user, that is, the user does not need to pass it, and the compiler completes it automatically .
2. Characteristics of this pointer
this
Pointers have the following properties :
this
The type of the pointer: the type* const
, that is, in the member function, cannot assignthis
a value to the pointer
void Init(int year, int month, int day)
{
//错误示例
this=nullptr;
}
- Can only be used inside member functions
this
A pointer is essentially a formal parameter of a member function . When an object calls a member function, the address of the object is passed to the formal parameter as an actualthis
parameter . So no pointer is stored in the objectthis
.this
The pointer is the first implicit pointer parameter of the member function . Generally, it is automatically passed by the compiler throughecx
the register and does not need to be passed by the user.
With this
pointers, the date class we implemented above can also be implemented like this:
//日期类
class Date
{
public:
void Init(int year, int month, int day)
{
this->_year = year;
this->_month = month;
this->_day = day;
}
void Print()
{
cout <<this-> _year << "-" <<this-> _month << "-" <<this-> _day << endl;
}
private:
int _year;
int _month;
int _day;
};
But there is no need to write this in the process of actually writing code, because the compiler has already done it for us, so we don't want to do thankless things.
【Interview questions】
this
Where do pointers exist ?
Answer: The this pointer is a formal parameter of a member function, so there is a stack area .this
Can a pointer be null ?
Look at the following two pieces of code:
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
// 2.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
void PrintA()
{
cout<<_a<<endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA();
return 0;
}
Choose C for the first course and B for the second course, because:
P
CallPrint
, will not be dereferenced, because the addressPrint
of is not in the object ,P
passed as an argument tothis
the pointer- Program 1:
this
The pointer is null, but the function does not dereferencethis
the pointer - The second program:
this
the pointer is empty, but access within the function_a
, the essence isthis->_a
, that is, dereferencing the null pointer, and an operation error will occur.
Nine. Comparison of C language and C++ implementation stack
1. C language implementation
typedef int DataType;
typedef struct Stack
{
DataType* array;
int capacity;
int size;
}Stack;
void StackInit(Stack* ps)
{
assert(ps);
ps->array = (DataType*)malloc(sizeof(DataType) * 3);
if (NULL == ps->array)
{
assert(0);
return;
}
ps->capacity = 3;
ps->size = 0;
}
void StackDestroy(Stack* ps)
{
assert(ps);
if (ps->array)
{
free(ps->array);
ps->array = NULL;
ps->capacity = 0;
ps->size = 0;
}
}
void CheckCapacity(Stack* ps)
{
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity * 2;
DataType* temp = (DataType*)realloc(ps->array,
newcapacity * sizeof(DataType));
if (temp == NULL)
{
perror("realloc申请空间失败!!!");
return;
}
ps->array = temp;
ps->capacity = newcapacity;
}
}
void StackPush(Stack* ps, DataType data)
{
assert(ps);
CheckCapacity(ps);
ps->array[ps->size] = data;
ps->size++;
}
int StackEmpty(Stack* ps)
{
assert(ps);
return 0 == ps->size;
}
void StackPop(Stack* ps)
{
if (StackEmpty(ps))
return;
ps->size--;
}
DataType StackTop(Stack* ps)
{
assert(!StackEmpty(ps));
return ps->array[ps->size - 1];
}
int StackSize(Stack* ps)
{
assert(ps);
return ps->size;
}
int main()
{
Stack s;
StackInit(&s);
StackPush(&s, 1);
StackPush(&s, 2);
StackPush(&s, 3);
StackPush(&s, 4);
printf("%d\n", StackTop(&s));
printf("%d\n", StackSize(&s));
StackPop(&s);
StackPop(&s);
printf("%d\n", StackTop(&s));
printf("%d\n", StackSize(&s));
StackDestroy(&s);
return 0;
}
It can be seen that when implemented in C language, Stack-related operation functions have the following commonality:
- The first parameter of each function is
Stack*
- The first parameter must be detected in the function , because the parameter may be
NULL
- In the function,
Stack*
the stack is manipulated through parameters. - The address of
Stack
the structure variable must be passed when calling
Only the structure for storing data can be defined in the structure , and the method of operating data cannot be placed in the structure, that is, the data and the way of operating data are separated , and the implementation is a bit more complicated, involving a large number of pointer operations, and errors may occur if you are not careful.
2. C++ implementation
typedef int DataType;
class Stack
{
public:
void Init()
{
_array = (DataType*)malloc(sizeof(DataType) * 3);
if (NULL == _array)
{
perror("malloc申请空间失败!!!");
return;
}
_capacity = 3;
_size = 0;
}
void Push(DataType data)
{
CheckCapacity();
_array[_size] = data;
_size++;
}
void Pop()
{
if (Empty())
return;
_size--;
}
DataType Top() {
return _array[_size - 1]; }
int Empty() {
return 0 == _size; }
int Size() {
return _size; }
void Destroy()
{
if (_array)
{
free(_array);
_array = NULL;
_capacity = 0;
_size = 0;
}
}
private:
void CheckCapacity()
{
if (_size == _capacity)
{
int newcapacity = _capacity * 2;
DataType* temp = (DataType*)realloc(_array, newcapacity *
sizeof(DataType));
if (temp == NULL)
{
perror("realloc申请空间失败!!!");
return;
}
_array = temp;
_capacity = newcapacity;
}
}
private:
DataType* _array;
int _capacity;
int _size;
};
int main()
{
Stack s;
s.Init();
s.Push(1);
s.Push(2);
s.Push(3);
s.Push(4);
printf("%d\n", s.Top());
printf("%d\n", s.Size());
s.Pop();
s.Pop();
printf("%d\n", s.Top());
printf("%d\n", s.Size());
s.Destroy();
return 0;
}
C++
Classes can be used to perfectly combine data and methods of manipulating data , and access rights can be used to control those methods that can be called outside the class , that is, encapsulation , which is more in line with human cognition of a thing, just like using its own members . Moreover, each method does not need to pass parameters , and the parameters will be automatically restored after the compiler compiles, that is, the parameters are maintained by the compiler, and the parameters need to be maintained by the user.Stack*
C++
Stack *
C语言
This is the end of this article, the code text is not easy, please support me a lot!