友元与运算符重载
友元
友元介绍
- 友元是一种允许非类成员函数访问类的非公有成员的一种机制
- 可以把一个函数指定为类的友元,也可以把整个类指定为另一个类的友元
- 友元函数
- 友元类
友元函数
- 友元函数在类的作用域外定义,但它需要在类体中进行说明;
- 为了与该类的成员函数加以区别,定义的方式是在类中用关键字 friend 说明该函数,格式如下:
friend 类型 友元函数名(参数表)
; - 友元的作用在于提高程序的运行效率。
- 友元函数虽然不是类的成员函数,但是可以访问类的私有的,公有的,保护的成员对象。
友元函数注意事项
- 友元函数不是类的成员函数,在函数体中访问对象的成员,必须用对象名加运算符‘.'加对象成员名。但友元函数可以访问类中的所有成员(公有的,私有的,保护的),一般函数只能访问类中的公有成员。
- 友元函数不受类中的访问权限关键字限制,可以把它放在类的公有,私有,保护部分,结果一样;
- 某类的友元函数的作用域并非该类的作用域。如果该友元函数是另一类的成员函数,则其作用域为另一类的作用域,否则与一般函数相同。
- 友元函数破坏了面向对象程序设计类的封装性,所以友元函数如果不是必须使用,则尽量少用,或用其他手段保证封装性。
友元类
- 如果某类 B 的成员函数会频繁的存取另一个类 A 的数据成员,而 A 的数据成员的 Private/Protected 限制造成 B 存取的麻烦,B 只能通过 A 的 public 的成员函数进行间接存取。
- 把 B 做成 A 类的友元类,即 A 类向 B 类开发其 Private/Protected 内容,让 B 直接存取。
- 友元类:一个类可以作为另一类的友元
- 友元类的声明:
friend class 类名;
友元类注意事项
- 友元关系是单向的:A 是 B 的友元类(在 B 类中 friend class A),并不代表 B 也是 A 的友元类;
- 友元关系不能被传递:A 是 B 的友元类,B 又是 C 的友元类,并不代表 A 是 C 的友元类;
- 友元关系不能被继承:A 是 B 的友元类,C 继承自 A,并不代表 C 是 B 的友元类。
运算符重载(一)
运算符重载
- 运算符重载允许把标志运算符(如 + - * / < > 等)应用于自定义数据类型的对象
- 直观自然,可以提高程序的可读性
- 体现了 C++ 的可扩充性
- 运算符重载仅仅只是语法上的方便,它是另一种函数调用的方式
- 运算符重载,本质上是函数重载
- 不要滥用重载,因为它只是语法上的方便,所以只有在涉及的代码更容易写,尤其是更容易读时才有必要重载。
成员函数重载
- 成员函数原型的格式:
函数类型 operator 运算符(参数表);
- 成员函数定义的格式:
类名::operator 运算发(参数表) {函数体}
Complex operator+(const Complex &other); // 声明 |
非成员函数重载
- 友元函数原型的格式
friend 函数类型 operator 运算符(参数表);
- 友元函数定义的格式
friend 函数类型 类名::operator 运算符(参数表){函数体;}
- 成员函数调用的优先级大于非成员函数
运算符重载规则
- 运算符重载不允许发明新的运算符
- 不能改变运算符操作对象的个数
- 运算符被重载后,其优先级和结合性不会改变
- 不能重载的运算符:::、 ?:、 .、 .*、 sizeof
- 一般情况下,单目运算符最好重载为类的成员函数,双目运算符最后重载为类的友元函数
- 以下一些双目运算符不能重载为类的友元函数:= () [] ->
- 类型转换运算符只能以成员函数方式重载
- 流运算符只能以友元的方式重载
运算符重载(二)
++ 运算符重载
前置 ++ 运算符重载
- 成员函数的方式重载,原型为:
函数类型 & operator++()
- 友元函数的方式重载,原型为:
friend 函数类型 & operator++(类类型 &);
后置自增和后置自减的重载
- 成员函数的方式重载,原型为:
函数类型 &operator++(int)
- 友元函数的方式重载,原型为:
friend 函数类型 &operator++(类类型 &,int)
;
// 前置 ++ |
!运算符重载
当字符串非空的时候返回真,字符串空的时候返回假
bool operator !() const; |
赋值运算符重载
当赋值操作时,默认是浅拷贝的,需要重载为深拷贝。
String& operator= (const String& other); |
运算符重载(三)
String类实现
[] 运算符重载
|
- static_cast < type-id > ( expression ),该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。
- dynamic_cast < type-id > ( expression )
说明:该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。 - const_cast<type_id> (expression)
说明:该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
常量指针被转化成非常量指针,并且仍然指向原来的对象;常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。
+ 运算符重载
// 以友元的方式重载 |
+= 运算符重载
MyString& operator+=(const MyString& other); |
流运算符c重载
- C++ 的 I/O 流库的一个重要特性就是能够支持新的数据类型的输出和输入
- 用户可以通过对插入符(<<) 和提取符 (>>)进行重载来支持新的数据类型
- 流运算符的重载只能使用友元函数进行重载
- 为什么一定要用友元函数进行重载?第一个参数是流对象,不是自身,返回的是流对象的引用。
friend istream& operator>>(istream&, 类类型&);
friend ostream& operator<<(ostream&, const 类类型&);
// << 运算符重载 |
运算符重载(四)
类型转换运算符
- 必须是成员函数,不能是友元函数
- 没有参数(操作数是什么)
- 不能指定返回类型(其实已经指定了)
- 函数原型
operator 类型名();
- 可以将当前的类类型转换诶其他类型
// 类型转换 |
-> 指针运算符
//例子 |
operator new 和 operator delete
void* operator new(size_t size)
void operator delete(void* p)
void operator delete(void* p, size_t size)
void* operator new(size_t size,const char* file, long line)
void operator delete(void* p, const char* file, long line)
void* operator new[](size_t size)
void operator delete[](void* p)
void operator delete[](void* p,size_t size)
new 三种用法
- new operator
Test* p1 = new Test(100); // new operator = operator new + 构造函数的调用
- operator new 可以被重载
- placement new 直接返回已经存在的地址
// placement new |
|
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Zhkuo!
评论