Skip to content

1. 友元

友元(friend):在某些情况下,允许特定的非成员函数访问一个类的私有成员,同时仍然阻止一般的访问。友元是对类封装机制的一种补充。

如果一个函数或者类(A)与另一个类(B)存在这种友元关系(B声明A是它的朋友),那么这个函数或者类(A)就可以访问另一个类(B)的私有成员和保护成员。

友元的优缺点:

  • 优点:提高了程序的运行效率
  • 缺点:破坏了类的封装性和隐藏性,使得其他的非成员函数或者其他类的成员函数可以访问类的私有成员

友元分为两种:友元函数和友元类

1.1 友元函数

在函数声明前加friend,这个函数可以是全局函数,也可以是类的成员函数。

1.1.1 普通的全局函数作为类的友元函数

  • 友元函数是某些不是类的成员函数却能够访问类的所有成员函数
  • 类授予它特别的访问权
  • 友元函数的声明:
    • 在授权类中声明访问权限
    • 格式:friend 返回值类型 函数名(形参列表);
  • 友元函数不属于类,因此没有this指针
cpp
#include<iostream>
using namespace std;

class A
{
public:
    void memberFun();
    friend void globalFun_friend(const A&that);
    A(int , int);

private:
    int m_private;
protected:
    int m_protected;
};

void A::memberFun()
{
    cout << "成员函数" << endl;
    cout << "m_private = "<< m_private << ", m_protected = "<< m_protected << endl;
}

A::A(int data1 = 0, int data2 = 0) : m_private(data1), m_protected(data2)
{
    cout << "构造函数" << endl;
    cout << "m_private = "<< m_private << ", m_protected = "<< m_protected << endl;
}

void globalFun_friend(const A& that)
{
    cout << "友元函数" << endl;
    cout << "m_private = "<< that.m_private << ", m_protected = "<< that.m_protected << endl;
}

void globalFun(const A& that)
{
    cout << "全局函数" << endl;
    //cout << "m_private = "<< that.m_private << ", m_protected = "<< that.m_protected << endl; // 错误:非友元函数
}

int main()
{
    A a(1, 2);
    cout << endl;
    a.memberFun();
    cout << endl;
    //a.globalFun_friend(a); // 错误:globalFun_friend不是A类成员
    globalFun_friend(a);
    cout << endl;
    globalFun(a);
    return 0;
}

1.1.2 类的成员函数作为另一个类的友元函数

步骤:

  1. 声明不包含友元函数的类
  2. 定义包含友元函数的类,在类中声明友元函数(不加friend)
  3. 定义不包含友元函数的类,在类中声明友元函数(加friend)
  4. 实现友元函数

注意:必须先定义包含成员函数的类,才能将该成员函数作为其他类的友元函数,且该函数必须在两个类之后定义。

cpp
#include <iostream>
class Girl; // 前向声明

class Boy
{
public:
    void memberFunctionA(const Girl& objGirl);
};

class Girl
{
private:
    int privateData;
public:
    Girl(int data) : privateData(data) {}
    friend void Boy::memberFunctionA(const Girl& objGirl); // 声明友元
};

void Boy::memberFunctionA(const Girl& objGirl)
{
    std::cout << "Member function of Boy accessing privateData of Girl: " 
              << objGirl.privateData << std::endl;
}

int main()
{
    Boy objBoy;
    Girl objGirl(42);
    objBoy.memberFunctionA(objGirl);
    return 0;
}

1.2 友元类

友元类(Friend Class):允许一个类拥有对另一个类的私有成员的访问权限。如果类B是类A的友元类(类A声明B是它的朋友),那么类B的所有成员函数都可以访问类A的私有成员。

1.2.1 友元类的声明

格式:friend class 类名;

注意事项:

  • 友元声明以friend开头,只能出现在类的声明中
  • 为代码可读性,通常把所有友元声明放到类开头
  • 友元关系是单向的(B能访问A ≠ A能访问B)
  • 友元关系不可传递(B能访问A且A能访问C ≠ B能访问C)
cpp
#include<iostream>
using namespace std;

class B;
class A
{
public:
    A(int, int);
    void memberFun_A(const B& b);
    friend class B; // 声明B为友元类
private:
    int m_private_A;
protected:
    int m_protected_A;
};

class B
{
public:
    B(int, int);
    void memberFun_B(const A& a);
private:
    int m_private_B;
protected:
    int m_protected_B;
};

A::A(int data1, int data2) : m_private_A(data1), m_protected_A(data2) {}

void A::memberFun_A(const B& b)
{
    cout << "A的成员函数" << endl;
    cout << "m_private_A = " << m_private_A << ", m_protected_A = " << m_protected_A << endl;
    // 无法访问B的私有成员
}

B::B(int data1, int data2) : m_private_B(data1), m_protected_B(data2) {}

void B::memberFun_B(const A& a)
{
    cout << "A的成员" << endl;
    cout << "m_private_A = " << a.m_private_A << ", m_protected_A = " << a.m_protected_A << endl;
    cout << "B的成员" << endl;
    cout << "m_private_B = " << m_private_B << ", m_protected_B = " << m_protected_B << endl;
}

int main()
{
    A a(1, 2);
    B b(3, 4);
    a.memberFun_A(b);
    cout << endl;
    b.memberFun_B(a);
    return 0;
}

2. 静态

2.1 静态成员变量

在变量类型前加static声明静态成员变量。

格式:

cpp
class 类名 {
    static 类型 变量名;
};

静态成员变量特征:

  • 不属于对象,属于类本身
  • 不能在构造函数中初始化,必须在类外单独定义和初始化
  • 存放在全局区(可理解为受限的全局变量)
  • 访问方式:
    • 类名::静态成员变量名(推荐)
    • 对象名.静态成员变量名

作用:

  • 数据共享:所有类实例共享同一副本
  • 内存管理:程序生命周期内存在,不随对象销毁
  • 访问限制:可通过类名直接访问
  • 生命周期:与程序运行时间相同
  • 优化性能:单次内存分配,减少内存碎片
  • 实现设计模式(如单例模式)
cpp
#include<iostream>
using namespace std;

class Student
{
public:
    Student(int age) { m_age = age; } // 不能初始化静态成员
    static string s_name;
    int m_age;
};

string Student::s_name = "def"; // 类外初始化

int main()
{
    cout << "sizeof(Student) = " << sizeof(Student) << endl; // 不包含静态成员
    Student stu1(18);
    cout << "stu1.m_age = " << stu1.m_age << endl;
    cout << "stu1.s_name = " << stu1.s_name << endl;
    cout << "Student::s_name = " << Student::s_name << endl;
    
    Student stu2(20);
    stu2.s_name = "张三";
    cout << "stu2.m_age = " << stu2.m_age << endl;
    cout << "stu2.s_name = " << stu2.s_name << endl;
    cout << "stu1.s_name = " << stu1.s_name << endl; // 共享修改
    return 0;
}

2.2 静态成员函数

在成员函数前加static声明静态成员函数。

格式:

cpp
class 类名 {
    static 返回类型 函数名(形参表) { ... }
};

静态成员函数特征:

  • 没有this指针
  • 没有const属性
  • 访问方式:
    • 类名::静态成员函数()(推荐)
    • 对象名.静态成员函数()
  • 只能访问静态成员,不能访问普通成员
  • 普通成员函数可访问静态成员和非静态成员

作用:

  • 与类关联而非对象关联
  • 访问静态成员变量
  • 作为工厂函数创建对象
  • 实现单例模式
  • 性能优化(无对象依赖)
cpp
#include<iostream>
using namespace std;

class Student
{
public:
    Student(int age = 0) : m_age(age) {}
    
    void fun1() const
    {
        cout << "非静态成员函数" << endl;
        cout << "s_name = " << s_name << endl; // 可访问静态成员
        cout << "m_age = " << m_age << endl;   // 可访问非静态成员
    }
    
    static void fun2()
    {
        cout << "静态成员函数" << endl;
        cout << "s_name = " << s_name << endl; // 可访问静态成员
        // cout << m_age; // 错误:不能访问非静态成员
    }
    
private:
    static string s_name;
    int m_age;
};

string Student::s_name = "蔡徐坤";

int main()
{
    Student stu(18);
    cout << sizeof(Student) << endl;
    stu.fun1();
    cout << endl;
    
    stu.fun2();         // 通过对象访问
    Student::fun2();    // 通过类名访问
    return 0;
}

知识如风,常伴吾身