C++ :五、友元与static

(一)友元

友元在 C++ 中是一种特殊的存在,其主要作用是打破类的访问控制权限。类中的成员通过 public、private 和 protected 三种访问修饰符设置访问权限,private 和 protected 成员对类外部代码而言通常不可直接访问。但在某些特定场景下,我们期望特定函数或类能够访问这些受限成员,此时友元便发挥作用。

友元可以是函数,也可以是类。当一个函数被声明为某个类的友元函数时,该函数便能访问该类的所有成员,包括 private 和 protected 成员。例如,我们创建一个Circle类来表示圆,radius设为 private 成员:

class Circle 
{
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    // 声明友元函数
    friend double calculateArea(Circle c); 
};

// 友元函数的定义
double calculateArea(Circle c) 
{
    return 3.14 * c.radius * c.radius; 
}

在上述代码中, calculateArea函数被声明为Circle类的友元函数,因此它能够直接访问Circle类的 private 成员radius来计算圆的面积。

除了友元函数,还有友元类。当一个类 A 被声明为另一个类 B 的友元类时,类 A 的所有成员函数都可以访问类 B 的所有成员。这在一些复杂的类关系中极为有用,比如一个 “管理类” 需要对多个 “被管理类” 进行深度操作时。

class B 
{
private:
    int privateData;
public:
    B(int data) : privateData(data) {}
    // 声明A为友元类
    friend class A; 
};

class A
 {
public:
    void accessBData(B& b)
     {
        // 可以直接访问B的private成员
        cout << "Accessed private data of B: " << b.privateData << endl; 
    }
};

使用友元虽然便捷,但不可滥用。因为它破坏了类的封装性,过多使用可能导致代码可维护性下降。所以在使用友元时,要考量是否确有必要打破访问限制。

1.友元与运算符重载

友元在运算符重载中也有重要应用。以复数类Complex为例,我们希望重载+运算符实现复数相加:

class Complex
 {
private:
    double real;
    double imag;
public:
    Complex(double r = 0, double i = 0) : real(r), imag(i) {}
    // 声明友元函数用于运算符重载
    friend Complex operator+(const Complex& c1, const Complex& c2); 
};

Complex operator+(const Complex& c1, const Complex& c2) 
{
    return Complex(c1.real + c2.real, c1.imag + c2.imag);
}

通过将operator函数声明为Complex类的友元,我们可以直接访问类的私有成员,从而实现更自然的复数相加操作。(类的友元函数并不包含this指针,普通成员函数属于类的一部分,依赖于特定的对象实例来调用,所以需要this指针来明确操作的是哪个对象的数据。而友元函数不是类的成员函数,它只是被授予了访问类中私有和保护成员的特殊权限。)

2.友元与模板类

在模板类中,友元同样能发挥独特作用。假设有一个通用的Static模板类,我们可能希望特定的模板实例化版本或其他类能够访问其内部成员:

template <typename T>
class Stack 
{
private:
    T* data;
    int top;
public:
    Stack() : data(nullptr), top(-1) {}
    // 声明友元类
    template <typename U>
    friend class StackDebugger; 
};

template <typename U>
class StackDebugger 
{
public:
    static void printStackInfo(Stack<U>& s)
 {
        // 访问Stack类的私有成员进行调试输出
       cout << "Stack top: " << s.top << endl; 
    }
};

这样,StackDebugger类的printStackInfo函数就Stack类的私有成员,方便进行调试和监控。

(二)static

在 C++ 中,static 关键字用途广泛,这里主要聚焦其在类中的应用,即静态成员和静态成员函数。

1.静态成员

静态成员变量属于类,而非某个具体对象。这意味着无论创建多少个类的对象,静态成员变量仅存在一份实例,所有对象共享该变量。例如,我们创建一个Student类,希望统计创建的学生对象数量,此时可使用静态成员变量:

class Student 
{
private:
    static int studentCount; 
    string name;
public:
    Student(string n) : name(n)
     {
        studentCount++; 
    }
    ~Student()
    {
            studentCount--; 
    }
    static int getStudentCount()
     {
        return studentCount; 
    }
};

// 初始化静态成员变量
int Student::studentCount = 0; 

在上述代码中,studentCount是静态成员变量,每次创建对象时,其值增加;每次销毁对象时,其值减少。通过静态成员函数getStudentCount,我们可获取当前学生数量。

2.静态成员函数

静态成员函数同样属于类,而非某个对象。它只能访问静态成员变量和其他静态成员函数,无法访问非静态成员,因为非静态成员依赖于具体对象存在。就像上述的getStudentCount函数,作为静态成员函数,它只能访问静态成员变量studentCount。

(static函数同样不包含this指针,静态函数的主要目的是提供与类相关但不依赖于对象实例的功能。它们通常用于执行不依赖于对象状态的操作,例如执行通用的计算或访问静态成员变量。由于它们不依赖于任何对象的状态,所以不需要this指针)。

int main()
 {
    Student s1("张三");
    Student s2("李四");
    cout << "Total students: " << Student::getStudentCount() << endl; 
    return 0;
}

静态成员函数和变量在许多场景中都非常实用,比如在实现单例模式时,就会用到静态成员来确保全局仅有一个类的实例。

3.static 与多态

虽然静态成员函数不能参与多态,但静态成员变量可以在多态环境下发挥独特作用。例如,在一个继承体系中,基类和派生类共享同一个静态成员变量,通过这个变量可以实现一些跨类的统计或状态管理功能:

class Animal 
{
public:
    static int animalCount; 
    Animal() 
    {
        animalCount++;
    }
    virtual ~Animal() 
    {
        animalCount--;
    }
    virtual void makeSound() = 0;
};
int Animal::animalCount = 0;

class Dog : public Animal 
{
public:
       void makeSound() override
     {
        cout << "Woof!" << endl;
    }
};

class Cat : public Animal 
{
public:

    void makeSound() override 
    {
        cout << "Meow!" << endl;
    }
};

在这个例子中,animalcount统计了所有动物及其派生类对象的总数,无论对象是谁,都共享这个静态变量。

4.static 与命名空间

在命名空间中,static 关键字也有特殊含义。在文件作用域内使用 static 修饰变量或函数,这些变量和函数的作用域将被限制在当前文件中,对外不可见。这有助于避免不同文件之间的命名冲突,提高代码的模块化程度。例如:

// file1.cpp
static int filePrivateVar = 0;
static void filePrivateFunc() 
{
    // 函数实现
}

// file2.cpp
// 这里无法访问file1.cpp中的filePrivateVar和filePrivateFunc
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值