- 前言
- 面向对象的编程
- 类与对象
- 类定义
- 类声明,关键字class
- 类的访问控制
- 类方法定义,类名作用域解析
- 类的内联方法
- 类使用
- 类的对象
- 使用类方法,访问类数据
- 对象与数组
- 对象与指针
- this指针
- this指针的实质
- 常量this指针
- 后记
本篇开始进入C++的特色核心部分,类与对象。
面向对象的编程C语言是面向过程的编程,在设计某项功能时,首先考虑功能的流程,再考虑数据的表示方法。
C++是面向对象的编程,在设计某项功能时,需要同时考虑数据的表示方法,以及数据的使用和交互。
C++类是面向对象编程的具体体现,与C++结构类似,但与C结构不同。
类可以简单形容为类数据+类方法。
类与对象 类定义类定义包含类声明和类方法定义两部分。
类声明,关键字class关键字class
用于声明一个类,一个典型的简单类声明如下所示:
class SimpleClass{
private:
int a_;
public:
SimpleClass();
void set(int);
int get();
~SimpleClass();
};
类声明用于描述类的数据成员,以及类的成员函数的使用方式(原型)。数据成员简称类数据,成员函数又称类方法。
上面的类声明指出,SimpleClass
类有一个int数据成员a_
,四个类方法。
为了封装、隐藏数据,类提供了三种访问成员和方法的权限,public
公有,private
私有,protected
保护。
public
公有部分可以直接由程序访问。
private
私有部分只能被类的公有方法或者友元函数访问。
protected
保护部分与类继承相关。
通常,类数据放在private
部分中,而类方法放在public
部分中。
注意:如果某个类方法只在类内部使用,而不必与外部程序交互,则可以设计成私有方法。私有方法同样只能被公有方法或友元函数使用。
SimpleClass
中的a_
不能被程序直接访问,而类方法都是可以直接使用的。
注意:类的默认访问权限是private,结构的默认访问权限是public。
类方法定义,类名作用域解析声明一个类后,需要在类外定义每一个类的成员函数,也就是类方法定义。
定义类方法时,需要通过类名作用域解析指明函数所属的类,接着SimpleClass
的示例如下:
// declare_class.h
#ifndef DECLARE_CLASS_H
#define DECLARE_CLASS_H
class SimpleClass{
private:
int a_;
public:
SimpleClass();
void set(int);
int get();
~SimpleClass();
};
#endif
// define_class_method.cpp
#include "declare_class.h"
void SimpleClass::set(int a){
a_ = a;
}
int SimpleClass::get(){
return a_;
}
类方法可以访问类数据a_
,即使a_
是类私有的。
除了在类外定义成员函数外,也可以在类声明中直接定义成员函数,这些函数将自动成为内联函数,即类的内联方法,示例如下:
// declare_class.h
#ifndef DECLARE_CLASS_H
#define DECLARE_CLASS_H
class SimpleClass{
private:
int a_;
public:
SimpleClass();
void set(int);
int get();
void add(int x) { // inline method
a_ += x;
}
~SimpleClass();
};
#endif
这样SimpleClass::add(int)
就是一个内联函数。
也可以在类外定义类的内联方法,只需要在类方法定义时使用inline
即可。这两种方法是等效的:
// declare_class.h
#ifndef DECLARE_CLASS_H
#define DECLARE_CLASS_H
class SimpleClass{
private:
int a_;
public:
SimpleClass();
void set(int);
int get();
void add(int x); // inline method
~SimpleClass();
};
#endif
// define_class_method.cpp
#include "declare_class.h"
void SimpleClass::set(int a){
a_ = a;
}
int SimpleClass::get(){
return a_;
}
inline void add(int x) {
a += x;
}
注意:一般而言,内联函数都写在头文件中。因此类的内联方法最好也采用在类声明内定义成员函数的方式。
类使用 类的对象定义了一个类后,类就成为了一种新的类型,类名即类型名。类的变量就称作对象。创建类的变量,就是创建了类的一个对象:
// use_class.cpp
#include "declare_class.h"
void main(){
SimpleClass sc1;
}
sc1
就是SimpleClass
类的一个对象。
每个对象都有自己的内存空间,存储该对象自己的数据。但是,同一个类的所有对象共享一组类方法,类方法在内存中只有一个副本,不同对象调用的函数是一样的,不过调用函数使用的数据不同。
也可以使用new
来为对象开辟动态内存。
类方法(非静态)需要通过对象进行调用,采用成员运算符.
:
// use_class.cpp
#include "declare_class.h"
void main(){
SimpleClass sc1;
sc1.set(1);
int ret = sc1.get(); // 1
}
此时,类方法将使用调用它的对象的内部数据。
对象与数组实际上,定义一个类后,类名的使用就与其它类型没有区别了。例如可以创建对象数组,使用对象数组中的元素:
// use_class.cpp
#include "declare_class.h"
void main(){
SimpleClass sc_array[5];
sc_array[0].set(2);
}
对象与指针
对象指针的使用方法也与普通类型相同:
// use_class.cpp
#include "declare_class.h"
void main(){
SimpleClass* psc = new SimpleClass;
psc->set(3);
delete psc;
psc = nullptr;
}
this指针
类的每个成员函数,都有一个this
指针,该指针指向调用成员函数的对象。
this
指针是一个指针常量,也就是说this
只读。
可以在成员函数中通过*this
调用对象本身,可以使用->
调用对象的数据成员和成员函数,示例如下:
// define_class_method.cpp
#include "declare_class.h"
void SimpleClass::set(int a){
this->a_ = a;
// a_ = a; // equal
}
this指针的实质
this
实际上是类成员函数的一个形参,调用成员函数时,将把对象的地址作为实参传给this
。该形参是隐式存在的。
因此,this
是类的成员函数中的一个局部变量。
如果希望使用成员函数时不修改对象内部的数据,则可以令this
指向常量。
具体做法是在成员函数的参数列表后添加关键字const
,此时this
指针就变成一个类似className const * const的指针,示例如下:
// define_class_method.cpp
#include "declare_class.h"
int SimpleClass::get() const {
return a_;
}
这样,SimpleClass::get()
就不能修改对象中a_
的数据了。这样的函数被称为const成员函数。
注意:常量对象不能使用非const成员函数,因为非const成员函数不能保证调用的对象不被修改。
尽量将不修改对象数据的成员函数声明和定义为const成员函数。
后记下篇继续C++类,构造函数与析构函数。