友元是C++提供的一种破坏数据封装和数据隐藏的机制。
通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息。
可以使用友元函数和友元类。
为了确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元。
友元函数:
1 友元函数是在类声明中由关键字friend修饰说明的非成员函数,在它的函数体中能够通过对象名访问 private 和 protected成员
2 作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择。
3 访问对象中的成员必须通过对象名。
//5-6友元函数 #include<iostream> #include<cmath> using namespace std; class 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(3,4);cout << "The distance is:";cout << dist(p1,p2) << endl;return 0; }
友元类:
1 若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员。
2 声明语法:将友元类名在另一个类中使用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;//A是B的组件 } void B::set(int i){a.x = i; } void B::display(){a.display(); }
类的友元关系是单向的:
如果声明B类是A类的友元,B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有、保护数据。
5.5共享数据的保护
对于既需要共享、又需要防止改变的数据应该声明为常类型(用const进行修饰)。
对于不改变对象状态的成员函数应该声明为常函数。
常类型:
1 常对象:必须进行初始化,不能被更新。
const 类名 对象名
2 常成员:用const进行修饰的类成员:常数据成员和常函数成员
3 常引用:被引用的对象不能被更新。
const 类型说明符 &引用名
4 常数组:数组元素不能被更新
类型说明符 const 数组名[大小]
5 常指针:指向常量的指针
常对象例:
class A{ public:A(int i, int j){x = i; y = j;} private:int x,y; }; A const a(3,4);//a是常对象,不能被更新
常成员:用const修饰的对象成员
1 常成员函数:使用const关键字说明的函数。
常成员函数不更新对象的数据成员。
const关键字可以被用于参与对重载函数的区分
通过常对象只能调用它的常成员函数。
2 常数据成员:使用const说明的数据成员。
//5-7 常成员函数举例 #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,39);b.print();//调用void print() constreturn 0; }
//5-8 常数据成员举例 #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){}//常成员a只能在初始化列表中初始化,不能再函数体中赋值 void A::print(){cout << a << " : " << b << endl; } int main(){//建立对象a和b,并以100和0作为初值,分别调用构造函数,//通过构造函数的初始化例表给对象的场数据成员赋初值A a1(100), a2(0);a1.print();a2.print();return 0; }
常引用:
如果在声明引用时用const修饰,被声明的引用就是常引用。
常引用所引用的对象不能被更新。
如果用常引用做形参,便不会意外地发生对实参的更改。
//5-9常引用作形参 #include<iostream> #include<cmath> using namespace std; class 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; }