第八讲:友元
来源:互联网 发布:月相软件 编辑:程序博客网 时间:2024/06/05 08:37
友元
友元是C++提供的一种破坏数据封装和数据隐藏的机制。
通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息。
可以使用友元函数和友元类。
为了确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元。友元函数
友元函数是在类声明中由关键字friend修饰说明的非成员函数,在它的函数体中能够通过对象名访问 private 和 protected成员
作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择。
访问对象中的成员必须通过对象名。
#include <iostream>#include <cmath>class Point { //Point类声明public: //外部接口 Point(int x=0, int y=0) : x(x), y(y) { } int getX() { return x; } int getY() { return y; } friend float dist(Point &a, Point &b); private: //私有数据成员 int x, y;};float dist( Point& a, Point& b) { double x = a.x - b.x; double y = a.y - b.y; return static_cast<float>(sqrt(x * x + y * y));}int main() { Point p1(1, 1), p2(4, 5); cout <<"The distance is: "; cout << dist(p1, p2) << endl; return 0;}
- 友元类
若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员。
声明语法:将友元类名在另一个类中使用friend修饰说明。
class A { friend class B;public: void display() { cout << x << endl; }private: int x;}class B {public: void set(int i); void display();private: A a;};void B::set(int i) { a.x=i;}void B::display() { a.display();}
友元关系
友元关系是单向的;声明B类是A类的友元,B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有、保护数据。
友元关系不能传递;
友元关系不能继承。共用数据的保护
C++采用了不少的数据保护措施。最常用的是将数据成员设置成私有数据( private ),以增加数据的安全性和私密性。
但是,有时候要求数据在能共享的前提下不能被篡改,就需要借助其它手段了。
什么手段呢?可以采用const,即把要保护的数据定义为常量。常对象
在定义对象时指定对象为常对象。常对象中的数据成员为常变量,并且必须要有初值:例如:class Time // 类定义 { public: int hour, minute, sec; Time(int h,int m, int s) //构造函数 {hour=h; minute=m; sec=s} void set() { cout<<hour<<minute<<ses; } }; Time const t1(12,34,56); // 常对象定义注意:在所有的场合中,对象t1的所有数据成员都被保护,不能被修改。因此,凡是希望数据成员不能被改变的对象,可以声明为常对象。其声明格式为: 类名 const 对象名(参数表列); 或者: const 类名 对象名(参数表列); 两者等价。
如果一个对象被定义成常对象,那么不能调用该对象的非const 型成员函数,而系统隐含调用的构造函数和析构函数除外。如在上例中:Time const t1( 12,34,56); // 对, 定义t1为常对象t1.set(); // 错误,set 不是const 型,不能调用 为什么会这样?因为成员函数有可能修改数据成员,而成员函数的定义可能和成员函数的声明不在同一文件,系统没法检测。所以,系统只能统一拦截,不让用户调用常对象的成员函数,除非该成员函数被声明成 const 类型。 怎样才能引用常对象的成员函数呢?只需要把该成员函数声明为 const 类型,即常成员函数就行了。方法为: 函数返回类型 函数名(参数表列) const; 例如:void set() const; // 将函数声明成const 类型 常成员函数可以访问常对象中的数据成员,但仍然不能修改它们。 有时候编程要求必须修改某个常对象中的数据成员,如某个计数器count ,ANSI C++对此做了特殊的处理,将该数据成员 声明为 mutable,如:mutable int count;此时,常对象的数据成员count,就可以用常成员函数来访问和修改了。
#include <iostream.h>class Time //类定义{public: int hour, min, sec; Time(int=0,int=0,int=0); void set() // 非const成员函数 {cout<<hour<<min<<sec<<endl;} void set1( ) const // const成员函数 {cout<<hour<<" "<<min<<" "<<sec<<endl;}};Time::Time(int h,int m,int s){hour=h;min=m;sec=s;} int main(){ Time const t1(12,34,56); // 常对象定义 t1.set(); //错误,常对象不能调用该对象的非const 型成员函数。 t1.set1(); return 0;}
- 常对象成员
1)常数据成员:其作用和用法与一般常变量相似,在类的声明中,用关键词 const 来声明常数据成员,例如: const int hour;注意1 :常数据成员的初始化,不能采用在构造函数中对常数据成员赋初值的方法。如: Time::Time(int h) {hour=h;} //非法注意2 :只能通过构造函数的参数初始化表对常数据成员进行初始化,例如: class Time // 类定义 { public: const int h; Time(int hh):h(hh){} }; 在类外定义构造函数,初始化形式为: Time::Time ( int h ): hour ( h ) { } 在类中声明了某一个数据成员为常数据成员后,该类的所有对象中的该数据成员的值是不可改变的(不输入、不赋值),但可以是不同的(由每个对象的参数初始化表决定)。
2) 常成员函数
一般的成员函数可以引用本对象中的非const 数据成员,也可以修改它们。但如果成员函数声明为常成员函数,则只能引用本对象中的数据成员,而不能修改它们。如:
void get_Time( ) const; // const位置在最后
const 是函数类型的一部分,在声明函数和定义函数时都要用到 const 关键字。
常成员函数可以引用常数据成员,也可以引用非const数据成员;而常数据成员可以被常成员函数引用,也可以被非 const 成员函数引用。
|常对象成员
怎样使用?
1)类中如果一些数据成员需要保护,另一些数据成员不需保护,将需要保护的数据成员声明为 const ,以保证其值不被改变。
2)类中如果所有数据成员都需保护,可以将所有数据成员都声明成 const ,本对象的任何成员函数,都只能引用,不能改变它们。或者将这些数据成员所属的对象声明成const,只让本对象的const 成员函数可引用,但不能改变。
3)如果一个对象被定义成了常对象,只能调用其中的const成员函数,不能调用非const成员函数。
4)常成员函数不能调用另一个非const成员函数
#include <iostream.h> // 常成员函数举例1class Time{public: int hour, min, sec; Time(int=0,int=0,int=0); // 构造函数 void set1( ) const // const成员函数 { cin>>hour>>min>>sec; // 错误,常成员函数不允许修改常对象中数据成员的值 cout<<hour<<" "<<min<<" "<<sec<<endl; // 常成员函数可以访问常对象中的数据成员 }};Time::Time(int h,int m,int s){hour=h;min=m;sec=s;} void main(){ Time const t1(12,34,56); // 常对象定义 t1.set1();} 如果需要访问常对象中的成员函数,则需要将其声明为const,表示这是一个常成员函数。 #include <iostream.h> // 常成员函数举例2class Time{public: mutable int hour, min, sec; Time(int=0,int=0,int=0); void set1( ) const // const成员函数 { cin>>hour>>min>>sec; // mutable 数据成员,可以改变 cout<<hour<<" "<<min<<" "<<sec<<endl;}};Time::Time(int h,int m,int s){hour=h;min=m;sec=s;} int main(){ Time const t1(12,34,56); // 常对象定义 t1.set1(); return 0;}要修改常对象中某个数据成员的值,则可将该数据成员声明为mutable。举例:
- 常引用作形参
#include <iostream>#include <cmath>using namespace std;class Point { //Point类定义public: //外部接口 Point(int x = 0, int y = 0) : x(x), y(y) { } int getX() { return x; } int getY() { return y; } friend float dist(const Point &p1, const Point &p2);private: //私有数据成员 int x, y;};float dist(const Point &p1, const Point &p2) { double x = p1.x - p2.x; double y = p1.y - p2.y; return static_cast<float>(sqrt(x * x + y * y));}int main() { //主函数 const Point myp1(1, 1), myp2(4, 5); cout << "The distance is: "; cout << dist(myp1, myp2) << endl; return 0;}
- 常类型
常类型的对象必须进行初始化,而且不能被更新。
常对象:必须进行初始化,不能被更新。
const 类名 对象名
常引用:被引用的对象不能被更新。
const 类型说明符 &引用名
常数组:数组元素不能被更新(下一章介绍)。
类型说明符 const 数组名[大小]…
常指针:指向常量的指针(下一章介绍)。
class A{ public: A(int i,int j) {x=i; y=j;} ... private: int x,y;};A const a(3,4); //a是常对象,不能被更新
- 用const修饰的对象成员
常成员函数
使用const关键字说明的函数。
常成员函数不更新对象的数据成员。
常成员函数说明格式:类型说明符 函数名(参数表)const;这里,const是函数类型的一个组成部分,因此在实现部分也要带const关键字。
const关键字可以被用于参与对重载函数的区分
通过常对象只能调用它的常成员函数。
常数据成员
使用const说明的数据成员。
#include<iostream>using namespace std;class R {public: R(int r1, int r2) : r1(r1), r2(r2) { } void print(); void print() const;private: int r1, r2;};void R::print() { cout << r1 << ":" << r2 << endl;}void R::print() const { cout << r1 << ";" << r2 << endl;}int main() { R a(5,4); a.print(); //调用void print() const R b(20,52); b.print(); //调用void print() const return 0;}
#include <iostream>using namespace std;class A {public: A(int i); void print();private: const int a; static const int b; //静态常数据成员};const int A::b=10; A::A(int i) : a(i) { }void A::print() { cout << a << ":" << b <<endl;}int main() {/*建立对象a和b,并以100和0作为初值,分别调用构造函数,通过构造函数的初始化列表给对象的常数据成员赋初值*/ A a1(100), a2(0); a1.print(); a2.print(); return 0;}
常引用作形参
#include <iostream>#include <cmath>using namespace std;class Point { //Point类定义public: //外部接口 Point(int x = 0, int y = 0) : x(x), y(y) { } int getX() { return x; } int getY() { return y; } friend float dist(const Point &p1, const Point &p2);private: //私有数据成员 int x, y;};float dist(const Point &p1, const Point &p2) { double x = p1.x - p2.x; double y = p1.y - p2.y; return static_cast<float>(sqrt(x * x + y * y));}int main() { //主函数 const Point myp1(1, 1), myp2(4, 5); cout << "The distance is: "; cout << dist(myp1, myp2) << endl; return 0;}
- 第八讲:友元
- 第八讲
- 第八讲
- 第八周一(2)友元
- 王桂林讲C++之友元
- 第八讲 图片超链接
- 第八讲 数据库基础
- 第八讲 对话框2
- mongoDB第八讲:分片
- java第八讲
- Java基础第八讲
- Hadoop第八讲
- 第八讲 泛化物品
- 第八讲 拖放功能
- 第八讲:权限管理
- 第八讲 拦截器
- 第八讲 动态SQL
- 第八讲 虚拟存储
- 【拜小白opencv】39-形态学滤波4——闭运算
- ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
- U盘安装CentOS7全程笔记(需要在该系统以及更新的版本上验证特定触摸屏能否使用的情况)
- ios gzip 压缩字符串
- HTTP请求格式,C++传参数,C,C++,VC++,window的HTTP请求通用
- 第八讲:友元
- Python获取二维矩阵每列最大值
- JavaWeb
- atoi atof atol等系列函数
- hexo+NexT博客优化第二弹
- php面向对象编程笔记(1)
- 安卓页面跳转
- Ract-Native 调出dev menu的命令
- springmvc控制器controller单例问题