C++在C语言的基础上做了一些改进,使得C++具有了面向对象编程(Object Oriented Programming,OOP)的特性。其中最重要的改进就是提供了类的概念。可以说学习了C++却不会使用类的话,那么就没有学习到C++的精髓。
在接下来的几篇博文中,我将梳理一下自己学习C++中类的学习心得。类中涵盖的知识点非常庞杂,我不会把每个细节都写出来,我会沿着主线由浅入深来梳理,希望对看到这些博文且想了解类的你有所帮助。
类的基本思想是数据抽象和封装。数据抽象是一种把接口和实现分离的编程技术。类的接口包括用户所能够执行的操作,类的实现包括类的数据成员、负责接口实现的函数体和各种私有函数。
封装实现了类的接口和实现的分离。封装隐藏了类的实现,封装过后,用户只能访问类的接口,而不能访问类的实现。
类是一种将抽象转换为用户定义类型的C++工具,它将数据表示和操纵数据的方法组合成一个整体。例如一个日常生活时间类,时间对象有两个属性,小时和分钟,根据需要应该能够对每个日常事务所花的时间进行操作和显示。操作和显示就需要类的接口函数。
一般的类由两部分组成:
1. 类声明:以数据成员的方式描述数据部分,以成员函数(被称为方法)的方式描述接口函数。
2. 类方法定义:描述如何实现类成员函数。
简单地说,类声明给出了类的框架,而方法定义给出了类的细节。
在下面的代码中声明了一个Time类;类中有两个关键字private和public,它们描述了程序对类的成员的访问控制。由于隐藏数据是OOP的主要目的之一,所以数据成员一般放在private部分,而接口函数则放在public部分。
#ifndef MYTIME_H
#define MYTIME_H
#include
using namespace std;
class Time
{
//----------私有成员,类中的成员默认是私有的
private:
int hours;
int mintues;
//----------共有成员
public:
Time(); //默认构造函数
Time(int h, int m = 0); //显式构造函数
Time(const Time &); //拷贝构造函数
~Time(); //析构函数
void AddMin(int m);
void AddHour(int h);
void reset(int h = 0, int m = 0);
//------展示函数show() //在const函数中不可调用非const函数成员
void Time::show() const
{
cout << "hours:" << hours << " " << "mintues:" << mintues << " "<
使用类对象的程序可以直接访问类的公有成员,但是不能直接访问私有成员,要访问私有成员则需要公有成员间接地访问。例如在程序中定义一个Time类对象eating。可以通过eating访问公有成员show()函数,而不能直接用eating访问hours。
Time eating(1, 45);
eating.show(); //合法;
eating.hours; //非法,不能直接访问私有成员。
注:类的成员默认是私有的,但是为了严谨一般还是用private关键字注明,而结构体的成员默认是公有的。
1. 在类外定义一个成员函数时,需要使用域解析运算符(::)来标识函数所属的类。这意味着,不同的类中,可以定义同样的成员函数而互不影响。
例如:
void Time::AddMin(int m)
{
mintues += m;
hours += mintues / 60;
mintues %= 60;
}
2. 在声明一个类时,可以将成员函数的定义直接放入类中,此时函数默认是一个内联函数,不需要添加域解析符。但是为了方便代码阅读,一般不会将成员函数直接在类中实现。
在上面的代码中,成员函数show()就直接定义在了类的定义体中。
3. 也可以将函数的实现写进类声明的头文件中,但是一定要添加inline关键字,在C++中的头文件(.h)—详解(2)中曾经提到过原因,如果不让函数成为内联函数,当头文件被多个源文件引用时,会出现重定义。(有疑惑的可以点击上面的链接进入阅读博文)
上面代码中的,reset()函数就是采用内联函数的方式定义在了类定义的头文件中。
对象使用成员函数时使用成员运算符: .
例如:Time的一个对象eating调用show()函数。
eating.show();
当定义类的成员函数时,时常会出现const关键字是放在函数括号后面的情况,他的意思是这个函数不能修改调用它的那个对象的值。与返回值是否是常量无关。 为了保证数据的安全,在类的成员函数不修改对象的值时,应该尽量将成员函数定义为const成员函数。
void Time::show() const //const关键字被放在了函数名括号的后面
{
cout << "hours:" << hours << " " << "mintues:" << mintues << " "<
定义一个const对象与定义一个const普通对象一样,在对象前加上const 关键字, const对象是无法调用非const成员函数的,以免非const成员函数修改const对象的数据,这无疑降低了程序出错的可能性,而非const对象是可以调用const成员函数的。以下面的代码为例。
Time swiming(0, 45); //非const对象
const Time study(8, 5); //const对象只能调用const成员函数。
study.reset(0,0); //非法,const对象无法调用非const成员函数。
study.show(); //合法,show()是const成员函数。
swiming.show(); //合法;
当然了,在const函数中修改对象的值是非法的,编译器无法通过。
为了方便大家的理解,在这里贴出所有代码
//----mytime.h
#ifndef MYTIME_H
#define MYTIME_H
#include
using namespace std;
class Time
{
//----------私有成员,类中的成员默认是私有的
private:
int hours;
int mintues;
//----------共有成员
public:
Time(); //默认构造函数
Time(int h, int m = 0); //显式构造函数
Time(const Time &); //拷贝构造函数
~Time(); //析构函数
void AddMin(int m);
void AddHour(int h);
void reset(int h = 0, int m = 0);
//------展示函数show() //在const函数中不可调用非const函数成员
void Time::show() const //const关键字被放在了函数体的后面
{
cout << "hours:" << hours << " " << "mintues:" << mintues << " "<
//--mytime.cpp
#include
#include "mytime.h"
using namespace std;
//-------默认构造函数
Time::Time()
{
hours = mintues = 0;
cout << "调用默认构造函数" << endl;
}
//------显式的构造函数
Time::Time(int h, int m) :hours(h), mintues(m)
{
cout << "调用显式构造函数" << endl;
}
//------拷贝构造函数
Time::Time(const Time &t)
{
hours = t.hours;
mintues = t.mintues;
cout << "调用拷贝构造函数" << endl;
}
//------析构函数
Time::~Time()
{
cout << "调用了析构函数" << endl;
}
//-------小时相加
void Time::AddHour(int h)
{
hours += h;
}
//------分钟相加
void Time::AddMin(int m)
{
mintues += m;
hours += mintues / 60;
mintues %= 60;
}
//---test.cpp
#include
#include "mytime.h"
using namespace std;
const void fun()
{
cout << 1 << endl;
}
int main()
{
Time eating(1, 45);
eating.show(); //合法;
//eating.hours; //非法,不能直接访问私有成员。
Time swiming(0, 45); //非const对象
const Time study(8, 5); //const对象只能调用const成员函数。
//study.reset(0,0); //非法,const对象无法调用非const成员函数。
study.show(); //合法,show()是const成员函数。
swiming.show(); //合法;
system("pause");
return 0;
}
上面的结果和代码中都可以看到构造函数,析构函数以及拷贝构造函数,因为这三种函数是类非常重要的成员函数,因此下次进行单独讲解。
已完。。
参考书籍《C++ Primer 第五版》、《C++ Primer Plus 第六版》
【C++】C++类的学习(二)——构造函数、析构函数、拷贝构造函数以及this指针
【C++】C++类的学习(三)——运算符重载与友元函数
【C++】C++类的学习(四)——继承与虚函数
【C++】C++类的学习(五)——纯虚函数与模板类