C++ Primer Chapter 7 Classes

C++ Primer Chapter 7 Classes

用于创建无线网

netsh wlan set hostednetwork mode=allow ssid=NetName key=password

2024/05/30
类的基本思想是数据抽象 (data abstraction)封装(encapsulation)。数据抽象是一种依赖于 接口(interface)实现(implementation) 分离的编程(以及设计)技术。
类的接口包括用户所能执行的操作;类的实现则包括类的数据成员、负责接口实现的函数体以及定义类所需的各种私有函数。
封装实现了类的接口和实现的分离。封装后的类隐藏了它的实现细节,也就是说,类的用户只能使用接口而无法访问实现的细节。

7.1 定义抽象数据类型

7.1.1 设计Sales_data类

成员函数(member function)
使用改进的Sales_data类

在这里插入代码片

7.1.2 定义改进的Sales_data类

Note 定义在类内部的函数是隐式的inline函数。

定义成员函数

引入this
成员函数通过一个名为this的额外的隐式参数来访问调用它的那个对象。当我们调用一个成员函数时,用请求该函数的对象地址初始化this。
例如,如果调用

total.isbn();

则编译器负责把total的地址传递给isbn的隐式形参this,可以等价地认为编译器将该调用重写成了以下的形式:

//伪代码,用于说明调用成员函数的实际执行过程
Sales_data::isbn(&total)

任何自定义名为this的参数或变量的行为都是非法的。我们可以在成员函数体内部使用this。
因为this的目的总是指向“这个”对象,所以this是一个常量指针,我们不允许改变this中保存的地址。

引入const成员函数
相当抽象,没有理解来
类作用域和成员函数
编译器分两步处理类:
首先编译成员的声明,然后才轮到成员函数体(如果有的话)。
因此,成员函数体可以随意使用类中的其他成员而无需在意这些成员出现的次序。

在类的外部定义成员函数

7.1.3 定义类相关的非成员函数

Note 一般来说,如果非成员函数是类接口的组成部分,则这些函数的声明应该与类在同一个头文件内。

7.1.4 构造函数(constructor)

constructor
不同于其他成员函数,构造函数不能被声明成const的。
当我们创建一个const对象时,直到构造函数完成初始化过程,对象才真正取得其“常量”属性。因此,构造函数在const对象的构造过程中可以向其写值。
合成的默认构造函数
如果我们的类没有显式定义构造函数,那么编译器就会为我们隐式地定义一个默认构造函数。
编译器创建的构造函数又被称为合成的默认构造函数(synthesized defaule constructor)
对于大多数类来说,这个合成的默认构造函数将按照如下规则初始化类的数据成员:
▧ 如果存在类内的初始值,用它来初始化成员。
▧ 否则,默认初始化该成员。

某些类不能依赖于合成的默认构造函数

Note 只有当类没有声明任何构造函数时,编译器才会自动地生成默认构造函数。

WARNING 如果类包含有内置类型或复合类型的成员,则只有当这些成员全都被赋予了类内的初始值时,这个类才适用于合成的默认构造函数。

有的时候编译器不能为某些类合成默认的构造函数。
例如,如果类中包含一个其他类类型的成员且这个成员的类型没有默认构造函数,那么编译器将无法初始化该成员。
对于这样的类来说,我们必须自定义默认构造函数,否则该类将没有可用的默认构造函数。

定义Sales_data的构造函数

Best Practices 构造函数不应轻易覆盖掉类内的初始值,除非新赋的值与原值不同。如果你不能使用类内初始值,则所有构造函数都应该显示地初始化每个内置类型的成员。

注解:类内的初始值,应该是指声明时给变量赋的初始值
在类的外部定义构造函数

7.2.1 友元
类可以允许其他类或者函数访问它的非公有成员,方法是令其他类或函数成为它的友元(friend)。
如果类想把一个函数作为 它的友元,只需要增加一套以friend关键字开始的声明语句即可:

	friend Sales_data add(const Sales_data&, const Sales_data&);
	friend std::istream& read(std::istream&, Sales_data&);
	friend std::ostream& print(std::ostream&, const Sales_data&);

友元声明只能出现在类定义的内部,但是在类内出现的具体位置不限。友元不是类的成员也不受它所在区域访问控制级别的约束。

Tip 一般来说,最好在类定义开始或结束前的位置集中声明友元。

关键概念:封装的益处
封装有两个重要的优点:
▧ 确保用户代码不会无意破坏封装对象的状态。
▧ 被封装的类的具体实现细节可以随时改变,而无须调整用户级别的代码。
Note 尽管当类的定义发生改变时无须改变用户代码,但是使用了该类的源文件必须重新编译。

友元的声明
友元的声明仅仅指定了访问的权限,而非一个通常意义上的函数声明。如果我们希望类的用户能够调用某个友元函数,那么我们就必须在友元声明致亲爱再专门对函数进行一次声明。
注解:friend只是一个访问权限修饰符

7.5 构造函数再探

7.5.4 隐式的类类型转换

如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制,有时我们把这种构造函数称为转换构造函数(converting constructor)。

Note 能通过一个实参调用的构造函数定义了一条从构造函数的参数类型向类类型隐式转换的规则。

string null_book="9-999-99999-9";
//构造一个临死的Sales_data对象
//该对象的units_sold和revenue等于0,bookNo等于null_book
item.combine(null_book);

只允许一步类类型转换
编译器只会自动执行一步类型转换。
例如,因为下面的代码隐式地使用了两种转换规则,所以它是错误的:

//错误:需要用户定义的两种转换
//(1)把"9-999-99999-9"转换成string
//(2)再把这个(临时的)string转换成Sales_data
item.combine("9-999-99999-9");

如果我们想完成上述调用,可以显示地把字符串转换成string或者Sales_data对象:

//正确:显式地转换成string,隐式地转换成Sales_data
item.combine(string("9-999-99999-9");
//正确:隐式地转换成string,显式地转换成Sales_data
item.combine(Sales_data("9-999-99999-9"));

类类型转换不总是有效
抑制构造函数定义的隐式转换
在要求隐式转换的程序上下文中,我们可以通过构造函数声明为explicit加以阻止:

class Sales_data{
public:
	Sales_data()=default;
	Sales_data(const std::string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){}
	explicit Sales_data(const std::string &s):bookNo(s){}
	explicit Sales_data(std::istream&);
	
};

此时,没有任何构造函数能用于隐式地创建Sales_data对象,之前的两种用法都无法通过编译:

item.combine(null_book);		//错误:string构造函数是explicit的
item.combine(cin);				//错误:istream构造函数时explicit的

关键字explicit只对一个实参的构造函数有效。需要多个实参的构造函数不能用于执行隐式转换,所以无须将这些构造函数指定为explicit的。只能在类内声明构造函数时使用explicit关键字,在类外部定义时不应重复:

//错误:explicit关键字只允许出现在类的构造函数声明处
explicit Sales_data::Sales_data(istream &is){
	read(is,*this);
}

explicit构造函数只能用于直接初始化

发生隐式转换的一种情况是当我们执行拷贝形式的初始化时(使用=)。此时,我们只能使用直接初始化而不能使用explicit构造函数:

Sales_data item(null_book);		//正确:直接初始化
Sales_data item=null_book;		//错误:不能将explicit构造函数用于拷贝形式的初始化过程

Note 当我们用explicit关键字声明构造函数时,它将只能以直接初始化的形式使用。而且,编译器将不会在自动转换过程中使用该构造函数。

为转换显式地使用构造函数

//正确:实参是一个显式构造的Sales_data对象
item.combine(Sales_data(null_book));
//正确:static_cast可以使用explicit的构造函数
item.combine(static_cast<Sales_data>(cin));
  • 11
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园2.0是高校信息化建设的新阶段,它面对着外部环境变化和内生动力的双重影响。国家战略要求和信息技术的快速发展,如云计算、大数据、物联网等,为智慧校园建设提供了机遇,同时也带来了挑战。智慧校园2.0强调以服务至上的办学理念,推动了教育模式的创新,并对传统人才培养模式产生了重大影响。 智慧校园建设的解决之道是构建一个开放、共享的信息化生态系统,利用互联网思维,打造柔性灵活的基础设施和强大的基础服务能力。这种生态系统支持快速迭代的开发和持续运营交付能力,同时注重用户体验,推动服务创新和管理变革。智慧校园的核心思想是“大平台+微应用+开放生态”,通过解耦、重构和统一运维监控,实现服务复用和深度融合,促进业务的快速迭代和自我演化。 智慧校园的总体框架包括多端协同,即“端”,它强调以人为中心,全面感知和捕获行为数据。这涉及到智能感知设备、超级APP、校园融合门户等,实现一“码”或“脸”通行,提供线上线下服务端的无缝连接。此外,中台战略是智慧校园建设的关键,包括业务中台和数据中台,它们支持教育资源域、教学服务域等多个领域,实现业务的深度融合和数据的全面治理。 在技术层面,智慧校园的建设需要分期进行,逐步解耦应用,优先发展轻量级应用,并逐步覆盖更多业务场景。技术升级路径包括业务数据化、数据业务化、校园设施智联化等,利用IoT/5G等技术实现设备的泛在互联,并通过人工智能与物联网技术的结合,建设智联网。这将有助于实现线上线下一网通办,提升校园安全和学习生活体验,同时支持人才培养改革和后勤管理的精细化。 智慧校园的建设不仅仅是技术的升级,更是对教育模式和管理方式的全面革新。通过构建开放、共享的信息化生态系统,智慧校园能够更好地适应快速变化的教育需求,提供更加个性化和高效的服务,推动教育创新和人才培养的高质量发展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值