【C++ Primer Plus】学习笔记--第10章 对象和类


10.1 面向对象编程

面向对象编程(OOP)特性:

  • 抽象
  • 封装和数据隐藏
  • 多态
  • 继承
  • 代码的可重用性

10.2 抽象和类

P341

C++中的类

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

类规范由两部分组成: 类声明提供了类的蓝图,而方法定义则提供了细节。

  • 类声明:以数据成员的方式描述数据部分,以成员函数(被称为方法)的方式描述公有接口。
  • 类方法定义:描述如何实现类成员函数

注意】:声明类只是描述对象的形式,并没有创建类,在创建类之前,将没有用于存储值的空间

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

类设计尽可能将公有接口和实现细节分开,被称为封装
数据隐藏(将数据放在类的私有部分)也是一种封装,将实现细节隐藏在私有部分中,也是一种封装。将类函数定义和类声明放在不同的文件中,也是封装。

从使用者的角度看,只需要知道是成员函数的功能,并不关心使用的哪种方法。原则是将实现细节从接口设计中分离出来

技巧1】:常见的约定------将类名的首字母大写
技巧2】:数据项放在私有部分组成类接口的成员函数放在公有项


类和结构的唯一区别

类的默认访问类型为私有private,而结构是公有public

实现类成员函数

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

内联方法

其定义位于类声明的函数都将自动成为内联函数

代码如下(示例):

class Stock
{
    
    
	void set_tot() //方法一:类声明中定义
	{
    
    
		//...
	}
};

等价于

class Stock
{
    
    
	void set_tot()};
inline void Stock::set_tot()  //方法二:类外内联
{
    
    
	//...
}

方法使用了那个对象?

所创建的每一个类对象都有自己的存储空间,用来存储其内部变量,但同一个类的所有对象共享同一组类方法
在这里插入图片描述
在OOP中,调用成员函数被称为发送消息

使用类

使用成员运算符句点调用类公有方法。

Stack sta; //创建对象
sta.set_tot(); //调用类方法

10.3 类的构造函数和析构函数

P352

类构造函数,专门用于构造新对象、将值赋给它们的数据成员。

构造函数声明和定义

class Stock
{
    
    
public:
// constructor prototype with some default arguments
	Stock(const string& company, long shares = 0);
private:
	std::string m_company;
	long m_shares;
}
//construckor definition
Stock::Stock(const string& company, long shares)
{
    
    	
	m_company = company;
	m_shares = shares;
}

// 构造函数初始化列表
Stock::Stock(const string& company, long shares)m_company(company), m_shares(shares){
    
    }

默认构造函数

在创建对象时,如果类内当且仅当没有提供任何构造函数,则C++将自动提供默认构造函数

Stock::Stock(){
    
    }  //默认构造函数
//没有提供任意构造函数,下面创建正确
Stock stock1; //yes
//提供了非默认构造函数,下面的创建报错
Stock stock1; //no

这样做的原因可能是:想禁止创建未初始化的对象

注意】:通常,应初始化所有的对象,以确保所有成员一开始就有已知的合理值。

Stock first("Tom", 20); //调用有参构造函数
Stock second(); // 定义一个返回为Stock对象的函数
Stock third; //调用默认构造函数

析构函数

对象结束其生命周期,系统自动执行析构函数。作用:清理善后工作

如果构造函数使用new来分配内存,则析构函数将使用delete来释放内存。如果没有使用new,析构函数没有要完成的任务。

//析构函数原型
~Stock();
//析构函数定义
Stock::~Stock(){
    
    }

类中必须有析构函数。如果程序员没有提供析构函数,编译器将隐式地声明一个默认析构函数。并在发现导致对象被删除的代码后,提供默认析构函数的定义。

const成员函数

保证函数不会修改调用对象。

void show() const;

void Stock::show() const

技巧】:只要类方法不修改调用对象,就应将其声明为const

10.4 为啥要用到this指针呢?

P363

有时候方法可能涉及到两个对象时,需要使用C++的this指针

看下面的例子:

//比较两个对象,问题在于不能返回当前对象
const Stock& topval(const Stock& s) const
{
    
    
	if (s.val > val)
	{
    
    
		return s;
	}
	return ??? ;
}
//返回类型为引用意味着返回的是调用对象本身,而不是其他副本。

为了解决此问题,使用被称为this的特殊指针,this指针指向用来调用成员函数的对象

this指针指向调用对象的地址;*this引用调用对象。

10.5 对象数组

P368

用户通常要创建同一类的多个对象创建对象数组更为合适。

创建方法

Stock mystuff[4]; //creates an array of 4 Stock objects

Stock stocks[3] = {
    
    
Stock("NanoSmart", 12.5, 20),
Stock("Boffo Objects", 200, 2.0)
};

10.6 类作用域

P370

在类中定义的名称的作用域是整个类。

作用域为类的常量

不可以在类中直接创建const常量

class Stock{
    
    
const int Months = 12; // fails
}

因为声明类只是类的蓝图,在创建对象前,没有用于存储值的空间

类中的静态整数常量和枚举类型

第一种是类中声明一个枚举

class Stock{
    
    
enum {
    
    Months = 12}; // 枚举创建常量
int Stocks[Months]; //将常量用于数组
}
// 由于使用枚举只是为了创建符号常量,并不打算创建枚举类型的变量,因此不需要提供枚举名。

用这种方式声明枚举并不会创建类数据成员。所有对象都不包含枚举。Months只是一个符号名称,在类中遇到Months,编译器将会用12替换它。

另一种是使用关键字static

class Stock{
    
    
static const int Months = 12; // static创建整数常量
int Stocks[Months]; //将常量用于数组
}

该整数常量将与其他的静态变量存储在一起,不是存储在对象中

注意】:只有静态整数常量(int,char,bool),可以在类中初始化。

作用域内枚举(C++11)

传统的枚举有些问题

//无法编译,位于相同的作用域,发生冲突。
enum egg{
    
    small};
enum shirt{
    
    small};

C++11提供了一种新枚举,其枚举作用域为类

enum class egg{
    
    small};  //可以编译
enum class shirt{
    
    small};

C++98中,包含枚举结构的长度可能随系统而异。
C++11中,作用域内枚举的底层类型为int

10.7 抽象数据类型

P373

实现stack数据类型。

猜你喜欢

转载自blog.csdn.net/ZR_YHY/article/details/112133572