C++学习(七)

C++学习(七),第1张

C++学习(七) 目录 一、引言 二、友元 ------> 2.1、友元类 ------> 2.2、友元成员函数 ------> 2.3、其他关系 ------> 2.4、共同的友元 ------> 2.5、嵌套类 ------> 2.6、异常 ------> 2.7、RTTI ------> 2.8、类型转换符 一、引言

本章主要讲一下友元的使用和异常机制

二、友元

前面我们已经使用过友元函数,用于类的扩展接口,如重载赋值运算符。类并非只能拥有友元函数,还可以将类作为友元,之后类中的所有方法都可以访问原始类的私有成员、保护成员。
同时也可以做更加严格的限制,将特定的成员函数指定为另一个类的友元,至于哪些函数、类为友元是由类定义的,相当于这个类定义了哪些函数、类为友元,可以访问私有数据。所以友元并没有与访问限制的思想相驳,相反提高了公有接口的灵活性。

1、友元类

通常如果两个类互不相干,但类A可以控制类B,这个时候就可以使用友元类来实现

friend class remote;

友元声明可以位于公有、私有或保护部分,其位置无关紧要

class TV
{
private:
	int state;
	int volum;
	int maxchannel;
	int channel;
	int mode;	//antenna or cable
	int input;	//TV or DVD
public:
	friend class Remote;
	enum {off,on = 1};
	enum {minval,maxval = 20};
	enum {antenna,cable = 1};
	enum {Tv,DVD = 1};

	TV(int s = off,int vol = 30) : state(s),volum(30), maxchannel(125), channel(5),mode(antenna),input(Tv) {};
	void onoff() { state = (state == off) ? on:off;}
	void volup();
	void voldown();
	void channelup();
	void channeldown();
	void chagemode() { mode = (mode == antenna) ? cable:antenna;};
	void changeinput() { input = (input == Tv) ? DVD:Tv;};
	void setting_show() const;
};

class Remote
{
public:
	void onoff(TV & T) { T.state = (T.state == T.off) ? T.on:T.off;}	
	void volup(TV & T);
	void voldown(TV & T);
	void channelup(TV & T);
	void channeldown(TV & T);
	void setchannel(TV & T,int c);
	void chagemode(TV & T) { T.mode = (T.mode == T.antenna) ? T.cable:T.antenna;};
	void changeinput(TV & T) { T.input = (T.input == T.Tv) ? T.DVD:T.Tv;};
	void setting_show(TV & T) const;	
};

这样一个Remote类可以控制多个TV类

2、友元成员函数

如果想将一个类中的某个方法变成另一个类的友元,可以如下定义

class TV
{
public:
	friend void Remote::set_chan(TV & t,int n);
	......
}

需要注意几点
1、Remote::set_chan需要在TV声明前声明
2、在声明Remote类的时候,需要先声明一下TV类
3、Remote只能在TV前声明,不能定义,可以使用内联函数在TV下面定义

class TV

class Remote
{
public:
	void set_chan(TV & t,int n);
	......
}
class TV
{
public:
	friend void Remote::set_chan(TV & t,int n);
	......
}

inline void Remote::set_chan(TV & t,int n) { channel = n;}
......

类成员作为友元才需要这么做,如果是类作为友元,无需这么做

3、其他关系

如果有两个类,可以相互控制,内部都可以有对方的友元函数,也可以实现,需要注意的就是先声明两个类,再定义

4、共同的友元

如果一个函数需要访问两个类的私有数据,则可以将这个接口设置为两个类的友元函数

class student
{
private:
	friend void set num(student & s,player & p);
};

class player
{
	friend void set num(student & s,player & p);
};

同样需要注意,不要在声明的时候时间使用内联定义

5、嵌套类

在C++中,可以将类声明放在另一个类声明中,在另一个类中声明的被称为嵌套类。它通过提供新的类型类作用域来避免名称混乱。
1、包含类的成员函数可以使用或创建嵌套类的对象
2、仅当声明位于共有部分,才能在包含类的外面使用嵌套类,并且必须使用作用域解析符

嵌套类和包含

嵌套类不同于包含,包含意味着将一个类对象所谓另一个类的成员对象。而对类进行嵌套不会创建类成员,而是定义了一种类型,这种类型仅在包含嵌套类声明的类中有效

嵌套类的作用域

嵌套类的作用域和类的声明位置相同,分为私有部分、保护部分、公有部分,为哪个类型取决于声明的位置,如果声明在类的私有数据中,则只有该类的成员函数能使用和看到嵌套类

class student
{
private:
	class girl
	{
	
	};
};

如果想使用它可以用如下语句

student::girl std1;
嵌套类内部的访问权限

嵌套类内部的访问权限和普通类的访问权限相同,外部只能访问其公有部分

嵌套类是可以访问被嵌套类类的私有成员的

如下

class school
{
private:
	class student
	{
	private:
		std::string name;
		int age;
	public:
		student() : name("null"),age(0) {};
		student(const std::string s,int g) : name(s),age(g) {};
		virtual ~student(){};
		void show();
		void getSchName();
	};
	std::string name;
	int age;
	int num;
public:
	school() : name("null"),age(0),num(0) {};
	school(const std::string s,int g,int n = 0) : name(s),age(g),num(n) {};
	virtual ~school(){};
	void show();
};
#include"over_class.h"


void school::student::show()
{
	std::cout << "student name : " << student::name << std::endl
		<< "age : " << student::age < 

使用

#include"over_class.h"


int main()
{
	school sch1("universchool",12,2000);
	school::student std1("xiaomin",19);

	sch1.show();
	std1.show();
	return 0;
}

这里就不展开说了,后面遇到再细说

6、异常

系统在运行时,有时会遇到错误,导致程序无法运行下去,如申请过多内存等。C++中设置了几种机制来预防这种事情的发生。

a、abort()

abort会向标准错误流发送错误消息,然后终止程序,返回一个错误码告诉 *** 作系统(父进程等)处理失败。
也可以调用exit,其会刷新文件缓冲区。注意这两者都会直接终止程序,而不是返回main

#include"over_class.h"
#include "cstdlib"
using namespace std;
int abb_te(int a,int b)
{
	if(a < b)
		abort();
	else
		cout << "a - b = " << a - b << endl;

	return a - b;
}

int main()
{
	school sch1("universchool",12,2000);
	school::student std1("xiaomin",19);
	int res;
//	sch1.show();
//	std1.show();

	cout << "res = " << abb_te(20,15) << endl;

	cout << "res = " << abb_te(10,12) << endl;

	cout << "Bye~" < 

运行如下

a - b = 5
res = 5

已放弃 (核心已转储)

用gdb看一下

$ gdb use_class
GNU gdb (GDB) 7.6.1
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
For bug reporting instructions, please see:
...
Reading symbols from /data1/caoboxi/test/C++/abort_/use_class...done.
(gdb) run
Starting program: /data1/caoboxi/test/C++/abort_/use_class 
a - b = 5
res = 5

Program received signal SIGABRT, Aborted.

可以看到 收到了SIGABRT这个信号量,对于的就是abort接口

返回错误码

这个很熟悉,就是给函数返回错误码,这里就不详述了

异常:exceptionlei

这里不详细展开了,后面遇到再深入研究

RTTI

RTTI是运行阶段识别的简称,C++支持三个RTTI

dynamic_cast

dynamic_cast运算符能够回答 是否可以安全的将对象地址赋给特定类型的指针

student * std1 = dynamic_castsch1;

如果能安全的转换则返回对象的地址,否则返回空指针(0),其中指针也可以用引用代替,但是如果使用了引用,则无法使用特殊的引用值来指示失败

typeid和type_info 类

typeid运算符能够确定两个对象是否为同种类型。接受两种参数
1、类名
2、结果为对象的表达式

typeid返回一个对type_info的引用,其在头文件:typeinfo 中定义

7、类型转换符

C++的创始人认为C语言中的类型转换运算符太过于松散,所有C++更严格的限制了允许的类型传唤,并添加了四个类型转换运算符

1、dynamic_cast

该运算符的用途是能够在类层次结构中向上转换,而不允许其他转换,具体用法上面有讲过

2、const_cast

该运算符用于执行只有一种用于的类型转换,修改const为volatile

const_cast (expression)
3、type_name

该运算符可被隐式转换为expersion所属的类

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5692800.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存