类
类与对象
类和结构体的区别
- 结构体相当于是只有类的数据域。但其区别有不仅仅如此。
- 类除了数据域,还有函数域,即声明了方法,当然,一般其方法是在类外实现的。而结构体没有方法一说。
- 基本上,结构体外的任何函数都可以对结构体的数据域进行访问。
- 而类可以将数据域封装为私有属性,这样子就可以拒绝非成员函数对其数据域的访问。
基本概念
-
类、对象的定义
-
类:
- 是现实世界或思维世界中的实体在计算机中的反映。
- 类将数据以及这些数据上的操作封装在一起。
- 包括两部分:
- 属性(数据)--- 数据域 --- 一般封装为
private
- 行为(函数 / 方法)--- 函数域 --- 一般封装为
public
- 属性(数据)--- 数据域 --- 一般封装为
-
对象:
- 是具有类类型的变量。
-
-
类和对象的关系
- 对象是对客观事物的抽象,类是对对象的抽象。
- 类是一种抽象的数据类型。
- 对象是类的实例,类是对象的模板。
类的定义
类是对一群具有相同属性、相同行为的对象的描述(抽象)。
关键字:class
PS:
- 类名称首字母建议大写。
类的定义形式如下:
class Name // class --- 类名称
{
public:
; // 公有成员(外部接口)!任何外部函数都可以访问
private:
; // 私有成员。只允许本类中的函数访问。
protected:
; // 保护型成员,与继承有关
}; // ps:结尾的花括号是有一个分号的
说明:
-
类包括:
- 属性(数据)--- 数据域 --- 一般封装为
private
- 行为(函数 / 方法)--- 函数域 --- 一般封装为
public
- 属性(数据)--- 数据域 --- 一般封装为
-
public
与private
是访问权限修饰符。- 被
public
修饰的属性和函数可以在类内部和类外部被访问。 - 被
private
修饰的属性和函数只能在类内部被访问
- 被
-
成员函数可以访问本类中的任何成员。一般的做法是将需要被外界调用的成员函数指定为
public
,它们是类的对外接口。 -
有的函数并不是准备为外界调用的,而是为本类中的成员函数所调用的,就应该将它们指定为
private
。 -
一般只在类内部对成员函数进行声明,在类外部对成员函数进行定义/实现。
-
结尾的花括号是有一个分号的!!!
-
类的定义举例:
class Clock { private: int hour, minute, second; public: void setTime(int newH, int newM, int newS); void showTime(); };
-
成员函数定义方法:
/* 返回类型 类名::成员函数名(参数说明) // 类名:: --- 表示该函数是类的成员函数 { 函数体 } */ //例如: // Clock:: 表示该函数是其成员函数 void Clock::setTime(int newH, int newM, int newS) { hour = newH; // hour, minute, second 已在类中定义了! minute = newM; second = newS; }
-
整体程序如下:
#include <iostream> class Clock { private: int hour; int minute; int second; public: void setTime(int newH, int newM, int newS); void showTime(void); }; int main(void) { // Clock 是一个类型 // 通过这个类型去声明一个变量 // 该变量就称为对象! // 定义对象 Clock myClock; // 通过点运算符调用成员函数 myClock.setTime(8, 30, 30); myClock.showTime(); return 0; } /* 成员函数的实现 */ void Clock::setTime(int newH, int newM, int newS) { hour = newH; minute = newM; second = newS; } void Clock::showTime(void) { std::cout << hour << ":" << minute << ":" << second << std::endl; }
构造函数
构造函数
constructor
是一种特殊的成员函数
它为对象的初始化提供了功能更强,使用更方便的途径。
它在类实例化为对象时,为类开辟了内存空间。且进行了初始化的工作。
-
构造函数的定义形式:
/* 类名::类名(参数说明) { 初始化代码 } */
-
构造函数的特点(很重要!):
- 构造函数的名字必须与类名相同。
- 定义构造函数时不能指定返回类型。
- 构造函数的代码与其它函数一样。但一般不直接调用(显式调用)。
- 创建类的一个新对象时,会隐式地自动调用构造函数。
也就是说:
当程序中声明一个新对象时,程序会自动调用该对象所属类中的构造函数来初始化这个对象的状态! - 若在定义类时没有定义构造函数,C++ 会自动为该类创建一个缺省
default
的构造函数。
这个构造函数没有任何形式参数,且函数体为空! - 若是构造函数有形参,则创建对象时,必须携带实参,该实参会赋予构造函数的形参!
- 若是构造函数没有参数,则创建对象时,不能携带参数!
- 构造函数也可以重载!
-
默认构造函数
- 调用时可以不需要参数的构造函数都是默认构造函数。
- 当不定义构造函数时,编译器自动产生默认构造函数。
- 在类中可以自定义无参数的构造函数,也是默认构造函数。
- 全部参数都有默认形参值的构造函数也是默认构造函数。
- 无参和带默认形参值的构造函数不能同时出现,否则在调用创建不带参数的对象时会出现混淆。
-
例如:
#include <iostream> using namespace std; class DemoClass { public: DemoClass(int i); ~DemoClass(); private: ; }; DemoClass::DemoClass(int i) { cout << "Initial value is " << i << endl; } DemoClass::~DemoClass() { cout << "destructor " << endl; } int main(void) { DemoClass obj(300); /* 创建对象是会隐式地,自动调用构造函数,并将300作为参数值传递给构造函数的形参i。此时会自动调用构造函数为对象分配内存! 即创建对象时的实参会赋予构造函数的形参! */ cout << "This is the end main()" << endl; return 0; }
- 输出如下:
PS E:\linj\code> code class.cpp PS E:\linj\code> g++ .\class.cpp -o class PS E:\linj\code> .\class.exe Initial value is 300 This is the end main() destructor
- 输出如下:
-
构造函数的定义
class Clock { private: int hour; int minute; int second; public: Clock(); // 增加构造函数 Clock(int newH, int newM, int newS); // 增加构造函数的重载的声明! void setTime(int newH, int newM, int newS); void showTime(void); ~Clock(); // 增加析构函数 }; /* 构造函数的实现 */ Clock::Clock(int newH, int newM, int newS) : // 这个冒号后面跟的是初始化成员列表 hour(newH), minute(newM), second(newS) { // 初始化成员列表 /* 该成员列表的作用等同于: hour = newH minute = newM second = newS */ } // 这和上面那段代码是等价的。 Clock::Clock(int newH, int newM, int newS) // 这个冒号后面跟的是初始化成员列表 { hour = newH; minute = newM; second = newS; } /* 构造函数重载 重载的构造函数也需要在类中进行声明!!! 无参构造函数,创建函数数时不加任何参数,包括括号! 例如: Clock c; // 此时调用的是无参构造函数 */ Clock::Clock():hour(1), minute(1), second(1) { /* 该成员列表的作用等同于: hour = 1 minute = 1 second = 1 */ }
析构函数
功能和构造函数恰好相反!
析构函数destructor
也是一种特殊的成员函数,它在对象撤销时执行一些清理任务!
它在对象的生命周期结束时,回收对象的内存空间。
-
例如:
在建立对象时用new
开辟了一片内存空间,delete
会自动调用析构函数后释放内存! -
析构函数定义形式:
/* 类名::~类名() { } */
-
析构函数的特点
- 析构函数的名字必须时在类名前面加上一个波纹号
~
,以区别于析构函数。 - 定义析构函数时也不能指定返回类型。
- 在对象消亡时,隐式地自动调用析构函数。
也就是说,
当程序中一个对象作用结束时,程序会自动调用该对象所属类中定义的析构函数来清除这个对象所占的存储空间。 - 若在定义类时没有定义析构函数,C++ 会自动为该类创建一个缺省的析构函数。
这个缺省析构函数没有任何形式参数,且函数体为空!
- 析构函数的名字必须时在类名前面加上一个波纹号
-
例如:
#include <iostream> using namespace std; class DemoClass { public: DemoClass(int i); ~DemoClass(); private: ; }; DemoClass::DemoClass(int i) { cout << "Initial value is " << i << endl; } DemoClass::~DemoClass() { cout << "destructor " << endl; } int main(void) { DemoClass obj(300); cout << "This is the end main()" << endl; /* return 0;表示函数结束,其中创建的obj对象被销毁,即生命周期结束。 此时会自动调用析构函数来自动回收对象的内存! */ return 0; }
- 输出如下:
PS E:\linj\code> code class.cpp PS E:\linj\code> g++ .\class.cpp -o class PS E:\linj\code> .\class.exe Initial value is 300 This is the end main() destructor
- 输出如下: