Part5 数据的共享与保护 5.4类的友元5.5共享数据的保护

友元是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() const
    return 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;
}

 

posted @ 2017-12-03 23:17  LeoSirius  阅读(159)  评论(0编辑  收藏  举报