C++类基础(四)

访问限定符与友元
● 使用 public/private/protected 限定类成员的访问权限

//main.cpp
struct Str
{
//结构体默认的访问权限,可以省略
//public:
    int x = 0;
private:
    int y = 0;
};

int main()
{
    Str m_str;
    //OK: 在同一个翻译单元内,结构体struct Str { ... }以外的任何地方都可以访问公有成员x
    //更普遍地: 只要是公有成员,就可以在结构体外访问它
    std::cout << m_str.x << std::endl;

    //Error: 'y' is a private member of 'Str',即只能在结构体struct Str { ... }内访问私有成员y
    //结构体Str类内声明的成员函数即使在类外定义,也算作结构体struct Str { ... }内
    //更普遍地: 只要是私有成员,就只能在结构体内访问它
    std::cout << m_str.y << std::endl;
    return 0;
}

– 访问权限的引入使得可以对抽象数据类型进行封装

struct Str
{
    //结构体的成员(比如内部数据)完全暴露给用户,导致用户可以操作这些成员,当出现成员的增删或者修改等等,会使程序崩溃或出现未定义的行为
    int x = 0;
    int y = 3;
};

– 类与结构体缺省访问权限的区别

struct Student
{
    //当没有书写private或protected或public访问权限说明符时,以下四个成员都是公有成员,即结构体的缺省访问权限是public
    char Name[10];
    int Age = 0;
    char Sex = 'F';
    void memberfunction() { }
};

class Student
{
    //当没有书写private或protected或public访问权限说明符时,以下四个成员都是私有成员,即类的缺省访问权限是private
    char Name[10];
    int Age = 0;
    char Sex = 'F';
    void memberfunction() { }
};
struct Student
{
//当有访问权限说明符时,各个访问权限生效的区域如下
private:
    ... //private:之后,protected:之前的成员都是私有成员
protected:
    ... //protected:之后,public:之前的成员都是私有成员
public:
    ... //public:之后,};之前的成员都是私有成员
};
//将关键字struct更换成class,以上定义仍然符合C++语法标准

● 使用友元打破访问权限限制 关键字 —— friend

int main(); //main函数的声明
class Str2;
class Str
{
    friend int main(); //在类Str之前声明main函数,然后将main函数声明为类Str的友元,所以main函数内可以访问类Str中的private成员、protected成员和public成员,所以#1处的代码合法
    friend Str2; //在类Str之前声明类Str2,然后将类Str2声明为类Str的友元,所以类Str2内可以访问类Str中的private成员、protected成员和public成员,所以#2处的代码合法
    inline static int x = 3; //私有成员,类内访问
};
class Str2
{
public:
    void fun()
    {
        std::cout << "Use private member 'x' of class Str in class Str2: " << Str::x << std::endl; //#2 OK
    }
};
int main()
{
    std::cout << Str::x << std::endl; //#1 OK
    Str2 my_Str2;
    my_Str2.fun();
    return 0;
}

– 声明某个类或某个函数是当前类的友元 慎用!

int main();
class Str2;
class Str
{
    friend int main();
    friend Str2; //C++标准要求: 类Str2内可以访问类Str中所有的成员(即使是私有成员),反过来类Str不可以访问类Str2的protected成员和private成员
    inline static int x = 3;
};
class Str2
{
public:
    void fun()
    {
        std::cout << Str::x << std::endl; //OK
    }
};
int main()
{
    std::cout << Str::x << std::endl; //OK
    Str2 my_Str2;
    my_Str2.fun();
    return 0;
}
//同上面的例子
class Str
{
  inline static int x = 3;
};
class Str2
{
    //将类Str2声明为类Str的友元,类Str2对类Str依然保持内部成员所具有的访问限制属性
    friend Str;
    void fun()
    {
        std::cout << Str::x << std::endl; //Error: 'x' is a private member of 'Str'
    }
};
class Str4;
class Str
{
    inline static int x = 3;
    friend Str4; //OK,将Str4声明成private权限限制符合C++语法标准
};
class Str2
{
    inline static int x = 4;
protected:
    friend Str4; //OK,将Str4声明成protected权限限制符合C++语法标准
};
class Str3
{
    inline static int x = 5;
public:
    friend Str4; //OK,将Str4声明成public权限限制符合C++语法标准
};
class Str4
{
public:
    void showStrX()
    {
        std::cout << "Str::x: " << Str::x << std::endl; //OK
    }
    void showStrX2()
    {
        std::cout << "Str2::x: " << Str2::x << std::endl; //OK
    }
    void showStrX3()
    {
        std::cout << "Str3::x: " << Str3::x << std::endl; //OK
    }
};

int main()
{
    Str4 myStr;
    myStr.showStrX(); //输出3
    myStr.showStrX2(); //输出4
    myStr.showStrX3(); //输出5
    return 0;
}

在这里插入图片描述

void fun();
class Str
{
    inline static int x = 100;
    friend void fun();
};

void fun()
{
    std::cout << Str::x << std::endl; //OK
}
int main()
{
    fun();
    return 0;
}

在这里插入图片描述
– 在类内首次声明友元类或友元函数

class Str
{
    inline static int x = 100;
    friend class Str2; //首次声明友元类Str2,即使编译器由上往下解析并且之前没有类Str2的声明,编译器仍然会解析成功
    friend void fun(); //首次声明友元函数fun(),同上,编译器将fun()解析为友元函数
};
class Str2
{
    
};

void fun()
{
    
}

● 注意使用限定名称引入友元并非友元类(友元函数)的声明

void function(); //#1
class Str
{
    inline static int x = 100;
    friend class Str2; //首次声明友元类Str2,即使编译器由上往下解析并且之前没有类Str2的声明,编译器仍然会解析成功
    friend void fun(); //首次声明友元函数fun(),同上,编译器将fun()解析为友元函数
    friend void ::function(); //编译器不会将::function()解析为function()的声明,所以必须在#1处加上function()的声明
};

– 友元函数的类外定义与类内定义

class Str
{
    inline static int x = 100;
    friend class Str2 //Error: Cannot define a type in a friend declaration
    {
        
    }
};
class Str
{
    int x = 100;
    friend void fun();
};
void fun() //友元函数的类外定义
{
    Str val;
    std::cout << val.x << std::endl;
}
int main()
{
    fun();
    return 0;
}

在这里插入图片描述

– 隐藏友元( hidden friend ):常规名称查找无法找到(The Power of Hidden Friends in C++

class Str
{
    int x = 100;
    friend void fun() //fun()不是类Str的成员,是类Str的隐藏友元函数
    {
        Str val;
        std::cout << val.x << std::endl;
    }
};
int main()
{
    fun(); //全局域中无fun()的声明,常规名称查找无法找到,报错
    return 0;
}

● 好处:减轻编译器负担,防止误用

void fun(); //全局域中声明fun()或者在类内声明隐藏友元类外定义隐藏友元,见友元函数的类外定义
class Str
{
    int x = 100;
    friend void fun() //fun()不是类Str的成员,是类Str的隐藏友元
    {
        Str val;
        std::cout << val.x << std::endl;
    }
};

int main()
{
    fun(); //OK
    return 0;
}

● 改变隐藏友元的缺省行为:在类外声明或定义函数

class Str
{
    int x = 100;
    friend void fun(const Str& val) //隐藏友元有一个传入参数
    {
        std::cout << val.x << std::endl;
    }
};

int main()
{
    Str myStr;
    fun(myStr); //对fun()传入了Str类型的参数myStr,常规名称查找无法找到后,触发实参类型依赖查找ADL(Argument Dependent Lookup),会在类Str内检测是否有匹配的函数
    return 0;
}

在这里插入图片描述

参考
深蓝学院:C++基础与深度解析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值