栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

第10章 对象和类

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

第10章 对象和类

第10章 对象和类 1. 过程性编程和面向对象编程

过程性编程首先考虑要遵循的步骤,然后考虑如何表示这些数据。

面向对象编程首先不仅考虑表示数据,还要考虑怎样使用数据,其中数据(数据成员)和使用数据(成员函数或方法)组合成了一个类,可以利用类创建它的实例——对象。

2. 抽象和类

抽象是将问题的本质特征抽象出来,并根据特征来描述解决方案。

2.1 类型是什么

指定基本类型完成了三项工作:

  • 决定数据对象需要的内存数量
  • 决定如何解释内存中的位
  • 决定可使用数据对象执行的操作或方法

对于内置类型来说,这些有关操作的信息都内置到编译器中,但在C++中定义自定义的类型时,必须提供有关操作的信息。

2.2 C++中的类

类是一种将抽象转换为用户定义类型的C++工具,它将数据表示和操纵数据的方法组合成一个整洁的包。

类规范由两个部分组成:

  • 类声明:数据成员描述数据部分,成员函数(也叫方法)描述为公有接口
  • 类方法定义:描述如何实现类成员函数

接口的概念:

接口是一个共享框架,供两个系统交互时使用。

对于类,我们说是公共接口。公共是使用类的程序,接口由类提供的方法组成。

提示:要使用某个类,必须了解其公共接口;要编写类,必须创建其公共接口。

通常,C++程序员将接口(类定义)放在头文件中,并将实现(类方法的代码)放在源代码文件中。

例子:

//头文件中包含类定义
#ifndef FLAG	//防止重复包含类定义
#define FLAG

class Data 			//class关键字指出这些代码定义了一个类设计
{
    private:				//可以不必使用关键字private,类中刚开始默认是private访问控制
		int x;				//数据成员
    	float y;			//数据成员
    	void set_xy()		 //成员函数
        {
			x = 1;
             y = 1.2;
        }
   	public:
    	void show();			//成员函数可以就地定义,也可以用原型表示,再在其他地方给出函数定义
};					//分号不能掉
#endif

private和public描述了对类成员的访问控制。所以类对象只能直接访问类成员的public(公有)部分,要想访问对象的private(私有)部分,需要通过公有成员函数。

数据隐藏:防止程序直接访问数据。用户只需要知道成员函数的功能。

封装:将实现细节放在一起并将它们与抽象分开。

类和结构的区别:C++扩展了结构的功能,它们之间唯一的区别在于:结构的默认访问类型是public,而类为private。

2.3 实现类成员函数

为那些由类声明中的原型表示的成员函数提供代码。它有两个特殊的特征:

  • 定义成员函数时,使用**作用域解析运算符(::)**来标识函数所属的类,因为函数属于类作用域
  • 类方法可以访问类的private组件

定义位于类声明中的函数都将自动成为内联函数。也可以在类声明之外定义成员函数,将其成为内联函数,记得加上关键字inline。内联函数的特殊规则要求每个使用它的文件都对其进行定义,最简便的方法就是将内敛定义放在定义类的头文件中。

创建对象和声明变量一样。

要想使用对象的公有成员,得通过成员运算符(.)。在OOP中,调用成员函数被称发送消息。

创建的每个对象都有自己的存储空间,用于存储内部变量和类成员;但是同一个类的所有对象共享同一组方法。

2.4 使用类

用户只需知道类的接口即可。

2.5 修改实现

记住:修改方法的实现时,不应影响客户程序的其他部分。

2.6 小结

类设计步骤:提供类声明、实现类成员函数、像使用基本类型一样使用类。

典型的类声明格式:

class ClassName 		//关键字class 和 自定义类名
{
	private:
    	data member declarations			//数据成员声明
     public:
    	member function prototypes			//成员函数原型
};
3. 类的构造函数和析构函数

C++目标之一是让使用类对象就像使用标准类型一样,但是类对象直接创建数据成员没有初始值,可能在调用成员函数时直接使用的是随机值,所以需要在创建对象时对它进行初始化。

C++为了解决这个问题提供了构造函数,目的是在创建对象时,自动对对象进行初始化。

构造函数不同于其他函数的特征:

  • 名称与类名相同
  • 没有声明类型
3.1 声明和定义构造函数
//假设有一个类Stock,类中有数据成员int x, float y, double z
//在类中已经定义构造函数原型:Stock(int x_, float y_, double z_ = 0);
//在类外定义构造函数如下:
Stock::Stock(int x_, float y_, double z_)		//注意:构造函数的参数名不能跟类中数据成员名相同
{
	x = x_;
    y = y_;
    z = z_;
}
3.2 使用构造函数

使用构造函数有两种方式:显式调用构造函数、隐式调用构造函数。

Stock A = Stock(1, 1.1, 1.1);		//显式调用构造函数
Stock A(1, 1.1, 1.1);			//隐式调用构造函数
//使用new创建对象,调用构造函数
Stock *A = new Stock(1, 1.1, 1.1);

注意:可以使用对象成员运算符调用方法,但是无法调用构造函数。

3.3 默认构造函数

默认构造函数是在未提供显式初始值时,用来创建对象的构造函数。

如果类中没有提供任何构造函数,则C++自动提供默认构造函数。

定义默认构造函数的方式有两种:

  • 给已有构造函数的所有参数提供默认值
  • 通过函数重载定义一个没有参数的构造函数
3.4 析构函数

当对象过期时,程序将自动调用一个特殊的成员函数——析构函数,来完成对象的清理工作。如果类中没有提供析构函数,则编译器隐式声明一个默认的构造函数。

如果构造函数使用的是new分配对象内存,则析构函数需要用delete释放对象内存。

析构函数不同于普通成员函数的特征:

  • 函数名就是类名,类名前加~
  • 没有声明类型
  • 没有参数
3.5 应用

在默认情况下,将一个对象赋给另一个对象时,会将原对象的每个数据成员内容赋给目标对象相应的数据成员。

构造函数还可以用于给新对象赋值,但是会创建一个临时对象。

C++11可以使用列表初始化类对象,只要列表中提供与某个构造函数的参数列表相匹配的内容。

const成员函数,为了确保成员函数不会修改对象,应在函数的括号后面加上关键字const。

另外,除了显式和隐式调用构造函数外,还可以使用赋值将对象初始化为一个值,前提是构造函数只接受一个参数。可关闭这个特性。

4. this指针

为了解决调用成员函数来处理两个对象之间的比较问题,引入了this指针。当然也可以用运算符重载解决。

this指针指向用来调用成员函数的对象,每个成员函数都有this指针,注意this是对象的地址,*this才是对象本身。

例子:

//假设有类Stock,topval方法和数据total_val已经在类中声明
const Stock & Stock::topval(const Stock &s) const		//函数返回的是const Stock类型的引用 
{																
	if (s.total_val > total_val)				//返回的是参数对象
       	return s;
    else 									//返回调用方法的对象
       return *this; 
}
5. 对象数组

声明对象数组的方式与声明标准类型数组相同。

但是要注意对象数组的初始化,默认情况下声明对象数组,会调用默认的构造函数,也可以显示调用构造函数来为数组元素初始化,没有被初始化调用默认构造函数。

当然,如果类中有多个构造函数,可以为数组元素指定特定的构造函数。

例如:

const int Size = 4;
Stock stocks[Size] = {
	Stock("NanoSmart", 12.5, 20),
    Stock("NanoSmart", 12.5, 20),
    Stock("NanoSmart", 12.5, 20),
    Stock("NanoSmart", 12.5, 20)
};				//数组对象都初始化为了相同值
6. 类作用域

在类中定义的名称的作用域为整个类,这些名称在类中是已知的,在类外是未知的,需要根据上下文使用成员运算符(.)或间接成员运算符(->)或者作用域解析运算符(::)

6.1 作用域为类的常量

在创建对象前,没有存储数据成员的值的空间。为了创建一个由所有对象共享的常量有两种方法:

  • 在类中声明一个枚举,枚举为整型常量提供作用域为整个类的符号名称。只是为了创建符号常量,不需要提供枚举名。
  • 使用关键字static,声明的常量将存储于静态区,而不是存储于对象中,所以只有一个常量共对象共享。
6.2 作用域内枚举(C++ 11)

传统枚举可能出现在同一作用域的同名枚举量,从而引发冲突。

  1. 为了解决这个问题,C++11提供一种新枚举,其枚举量作用域为类。其声明格式如下:
enum class 枚举名 {枚举量列表};			//class可用struct代替
  1. C++11提供了作用域内枚举的安全,例如:常规枚举量会自动转换为整型,但是作用域内枚举不行,但是必要时可以显示类型转换。

  2. 默认情况下,作用域内枚举的底层数据类型是int,但是也可以指定数据类型,例如:

    enum class : short 枚举名 {枚举量列表};
    
7. 抽象数据类型ADT

ADT以通用方式描述数据类型,而没有引入语言或实现细节。类概念非常适合于ADT方法。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/879771.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号