C++学习之友元

简介: C++学习之友元

C++友元的介绍

在C++中,友元(friend)是一种特殊的关系,允许一个类或函数访问另一个类的私有成员。通过使用友元关键字,我们可以实现对其他类的私有成员的访问。

友元可以是一个类或函数,在提供存取权限时,不需要通过类的公有接口来访问私有数据。这对于某些特殊情况下需要访问类的私有成员而无需打破封装性的代码是非常有用的。

在C++中,友元的声明必须在类中进行,在类的声明中,可以使用friend关键字声明其他类或函数为友元。被声明为友元的类或函数可以自由地访问该类的私有成员。

以下是友元的一些特点:

友元关系是单向的,它不具备传递性。如果类A是类B的友元,类B不一定是类A的友元。

友元关系是非继承关系,即使派生类与基类具有友元关系,该友元关系对派生类没有影响。

友元关系破坏了类的封装性,因此应该谨慎使用。在设计类时,应考虑是否真正需要使用友元。

友元关键字的使用应该谨慎,并仅在确实需要访问其他类的私有成员时使用。过度使用友元关键字可能导致代码难以理解和维护。

C++ 全局函数做友元

在 C++ 中,全局函数作为类的友元可以用于多种情况,下面详细介绍并举例说明:

  1. 实现特定操作:全局函数可以访问类的私有成员,用于执行类的特定操作,尤其是那些需要直接访问私有数据的操作。
class MyClass {
private:
    int privateData;
public:
    MyClass(int data) : privateData(data) {}
    friend void globalFunction(MyClass& obj); // 将全局函数声明为友元
};
void globalFunction(MyClass& obj) {
    obj.privateData = 100; // 访问 MyClass 的私有成员 privateData
}
  1. 对多个类进行操作:全局函数作为多个类的友元,可以跨类访问私有成员,方便实现类之间的协作操作。
class ClassA;
class ClassB {
private:
    int privateValue;
public:
    friend void globalFunction(ClassA& a, ClassB& b);
};
class ClassA {
private:
    int secretNumber;
public:
    friend void globalFunction(ClassA& a, ClassB& b);
};
void globalFunction(ClassA& a, ClassB& b) {
    a.secretNumber = 42;
    b.privateValue = 10;
}
  1. 提高程序设计灵活性:通过友元关系,全局函数能够更自由地对类的私有成员进行操作,提高程序设计的灵活性和可扩展性。
  2. 解决特定问题:有时某些问题只能通过特殊的操作来解决,全局函数作为友元提供了这样的机会,使得代码更加清晰和易于维护。
class TemperatureConverter {
private:
    double temperature;
public:
    TemperatureConverter(double temp) : temperature(temp) {}
    friend void convertToFahrenheit(TemperatureConverter& converter);
};
void convertToFahrenheit(TemperatureConverter& converter) {
    double fahrenheit = (converter.temperature * 9 / 5) + 32;
    cout << "Temperature in Fahrenheit: " << fahrenheit << endl;
}

全局函数作为类的友元可以帮助我们在一些特定情况下访问类的私有成员,并进行一些需要私有数据支持的操作。然而,在使用时需要注意平衡封装性和灵活性,避免过度暴露类的私有信息。

C++友元类

在 C++ 中,友元类是允许一个类访问另一个类的私有成员的特殊机制,即一个类可以将另一个类声明为自己的友元类。下面是关于友元类的各种情况的详细介绍和代码示例:

  1. 让类之间能够互访私有成员
    友元类的主要目的是让两个或多个类能够互相访问彼此的私有成员。通过将一个类声明为另一个类的友元类,允许友元类的成员函数访问该类的私有成员。
class ClassB; // 前向声明
class ClassA {
private:
    int privateData;
public:
    ClassA(int data) : privateData(data) {}
    friend class ClassB; // 将 ClassB 声明为 ClassA 的友元类
};
class ClassB {
public:
    void accessPrivateData(ClassA& obj) {
        obj.privateData = 10; // ClassB 可以访问 ClassA 的私有成员
    }
};
int main() {
    ClassA obj(5);
    ClassB b;
    b.accessPrivateData(obj); // 调用 ClassB 对象的函数来访问 ClassA 的私有成员
    return 0;
}
  1. 方便多个类之间的交互
    友元类关系使得多个类之间能够直接访问彼此的私有成员,从而方便地实现类之间的交互和操作。
class ClassB; // 前向声明
class ClassA {
private:
    int privateData;
public:
    ClassA(int data) : privateData(data) {}
    friend class ClassB; // 将 ClassB 声明为 ClassA 的友元类
};
class ClassB {
private:
    int privateValue;
public:
    ClassB(int value) : privateValue(value) {}
    void accessPrivateMembers(ClassA& obj) {
        obj.privateData += privateValue; // ClassB 可以访问和修改 ClassA 的私有成员
    }
};
int main() {
    ClassA objA(5);
    ClassB objB(10);
    objB.accessPrivateMembers(objA); // ClassB 的成员函数访问 ClassA 的私有成员
    return 0;
}
  1. 提高灵活性和可扩展性
    友元类的存在可以在一定程度上提高程序的灵活性和可扩展性。它允许某些特定的类或函数直接访问私有成员,从而实现更灵活的设计和编码。
class Logger; // 前向声明
class MyClass {
private:
    int privateData;
    void logData(Logger& logger); // 声明一个接受 Logger 对象的私有函数
    friend class Logger; // 将 Logger 声明为 MyClass 的友元类
};
class Logger {
public:
    void log(MyClass& obj) {
        obj.logData(*this); // 允许 Logger 的成员函数访问 MyClass 的私有函数
    }
};
void MyClass::logData(Logger& logger) {
    // 通过 Logger 的对象记录 MyClass 的私有数据
    logger.log("MyClass private data: " + std::to_string(privateData));
}
int main() {
    MyClass obj;
    Logger logger;
    logger.log(obj); // 通过 Logger 记录 MyClass 的私有数据
    return 0;
}

友元类提供了一种允许一个类访问另一个类的私有成员的机制。它可以方便实现类之间的交互和操作,并提供更灵活的设计和编程方式。需要小心使用友元类,以确保封装性和安全性不会被破坏。

C++成员函数做友元

朋友多了路好走


在 C++ 中,一个类的成员函数可以作为另一个类的友元函数,从而允许该成员函数访问另一个类的私有成员。这种情况下,友元函数并不属于友元类,而是属于另一个类的成员函数。下面是关于成员函数作为友元的各种情况的详细介绍以及相关代码示例:

  1. 让某个类中的成员函数可以访问其他类的私有成员
    一个类的成员函数可以被声明为另一个类的友元函数,以使得该成员函数能够访问其他类的私有成员变量。
class ClassB; // 前向声明
class ClassA {
private:
    int privateData;
public:
    ClassA(int data) : privateData(data) {}
    void friendFunction(ClassB& obj); // 将 ClassB 的成员函数声明为 ClassA 的友元函数
};
class ClassB {
public:
    void friendFunction(ClassA& obj) {
        obj.privateData = 10; // ClassB 的成员函数可以访问 ClassA 的私有成员 privateData
    }
};
int main() {
    ClassA objA(5);
    ClassB objB;
    objB.friendFunction(objA); // 调用 ClassB 的成员函数来访问 ClassA 的私有成员
    return 0;
}
  1. 提高类之间的互操作性
    使用成员函数作为友元函数可以增强类之间的互操作性,即使两个类之间没有明确的继承或关联关系,也能方便地访问对方的私有成员。
class ClassB; // 前向声明
class ClassA {
private:
    int privateData;
public:
    ClassA(int data) : privateData(data) {}
    void friendFunction(ClassB& obj); // 将 ClassB 的成员函数声明为 ClassA 的友元函数
};
class ClassB {
private:
    int privateValue;
public:
    ClassB(int value) : privateValue(value) {}
    void friendFunction(ClassA& obj) {
        obj.privateData += privateValue; // ClassB 的成员函数可以访问和修改 ClassA 的私有成员 privateData
    }
};
int main() {
    ClassA objA(5);
    ClassB objB(10);
    objB.friendFunction(objA); // 通过 ClassB 的成员函数实现对 ClassA 的私有成员的操作
    return 0;
}
  1. 解决特定问题
    有时候某个类中的成员函数需要访问另一个类的私有成员来解决特定问题,此时将另一个类的成员函数声明为友元函数能够更方便地实现需求。
class DataProcessor; // 前向声明
class DataManager {
private:
    int data;
public:
    DataManager(int value) : data(value) {}
    void processData(DataProcessor& processor); // 声明 DataProcessor 的成员函数为友元函数
};
class DataProcessor {
public:
    void processAndDisplayData(DataManager& manager) {
        // 可以访问 DataManager 的私有成员 data
        cout << "Processed data: " << manager.data * 2 << endl;
    }
};
void DataManager::processData(DataProcessor& processor) {
    processor.processAndDisplayData(*this); // 调用 DataProcessor 的成员函数处理 DataManager 的数据
}
int main() {
    DataManager dataManager(5);
    DataProcessor dataProcessor;
    dataManager.processData(dataProcessor); // 处理 DataManager 的数据
    return 0;
}

将一个类的成员函数声明为另一个类的友元函数可以方便地解决特定问题,提高类之间的互操作性,并允许成员函数访问其他类的私有成员。在使用时要注意权衡封装性和灵活性,确保友元关系不会破坏类的封装性。

C++友元的应用场景

友元在 C++ 中的应用场景包括但不限于以下几种情况:

  1. 运算符重载:友元函数可以被用来重载操作符,比如重载 <<>> 运算符用于自定义类对象的输入输出。
class MyClass {
private:
    int value;
public:
    MyClass(int v) : value(v) {}
    friend std::ostream& operator<<(std::ostream& os, const MyClass& obj);
};
std::ostream& operator<<(std::ostream& os, const MyClass& obj) {
    os << "Value: " << obj.value;
    return os;
}
int main() {
    MyClass obj(100);
    std::cout << obj;  // 使用重载的 << 运算符输出对象
    return 0;
}
  1. 原生数据类型转换:有时候需要在类之间进行类型转换,可以使用友元函数实现。
class Dollars;
class Euros {
private:
    float amount;
public:
    Euros(float a) : amount(a) {}
    friend float convertToDollars(const Euros& e);
};
float convertToDollars(const Euros& e) {
    return e.amount * 1.2;  // 假设汇率为 1.2
}
int main() {
    Euros e(100);
    std::cout << "Dollars: " << convertToDollars(e) << std::endl;
    return 0;
}
  1. 不同类之间的协作:当两个类之间存在特定关系时,一个类的成员函数可以作为另一个类的友元函数,以方便访问私有成员。
class ClassB;
class ClassA {
private:
    int privateData;
public:
    ClassA(int data) : privateData(data) {}
    friend void ClassB::friendFunction(ClassA& obj);
};
class ClassB {
public:
    void friendFunction(ClassA& obj) {
        obj.privateData = 10; // ClassB 的成员函数可以访问 ClassA 的私有成员 privateData
    }
};
int main() {
    ClassA objA(5);
    ClassB objB;
    objB.friendFunction(objA); // 调用 ClassB 的成员函数访问 ClassA 的私有成员
    return 0;
}
  1. 提供更高层次的抽象:友元函数可以提供类的更高层次的抽象,将一些不直接属于对象的非成员函数与类相关联,但仍能访问私有成员。

友元提供了一种灵活的方式来访问类的私有部分,但需要小心使用以避免破坏封装性。友元应该在确实无法通过其他方式满足需求的情况下使用,并且在使用时要慎重考虑其影响。

C++ 友元使用注意事项

在使用 C++ 中的友元时,需要注意以下几个事项:

  1. 尽量避免过度使用友元:友元破坏了类的封装性和抽象性,使得类之间的关系更加耦合。因此,应该尽量避免过度使用友元,只在确实无法通过其他方式满足需求的情况下使用。
  2. 友元是双向的:友元关系是一种双向的关系。如果将类 A 声明为类 B 的友元,那么类 B 也自动成为类 A 的友元。这意味着类 B 可以访问类 A 的私有成员,但同时也意味着类 A 可以访问类 B 的私有成员。因此,在声明友元关系时要慎重考虑,确保双方都需要直接访问对方的私有成员。
  3. 友元函数和友元类:除了可以将函数声明为类的友元外,还可以将另一个类声明为友元。当将一个类声明为另一个类的友元时,被声明的类可以访问友元类的私有成员。友元类的使用要小心,因为它通常会导致高度耦合的设计,可能违背面向对象的原则。
  4. 友元不继承:友元关系不会被继承。子类不会自动继承父类的友元关系,即使子类可以访问父类的私有成员,仍然无法通过子类来访问父类的友元类或友元函数。
  5. 使用封装的友元函数:为了限制友元的访问范围,可以将友元函数定义为类的私有或保护成员,并通过公有接口间接调用该友元函数。这样可以避免友元过于暴露,提高封装性。
  6. 考虑替代方案:在使用友元之前,可以考虑其他可能的替代方案,例如使用成员函数或访问器方法来访问私有成员,或者重新设计类的层次结构以避免需要友元关系。

友元是一种特殊的关系,可以在一些特定情况下解决问题。但由于友元破坏了封装性,因此在使用时需要谨慎考虑,权衡利弊,并确保友元的使用符合设计原则和需要。

关注我,不迷路,共学习,同进步

关注我,不迷路,共学习,同进步

相关文章
|
2月前
|
存储 编译器 C++
【C++】深入探索类和对象:初始化列表及其static成员与友元(一)
【C++】深入探索类和对象:初始化列表及其static成员与友元
|
1天前
|
算法 网络安全 区块链
2023/11/10学习记录-C/C++对称分组加密DES
本文介绍了对称分组加密的常见算法(如DES、3DES、AES和国密SM4)及其应用场景,包括文件和视频加密、比特币私钥加密、消息和配置项加密及SSL通信加密。文章还详细展示了如何使用异或实现一个简易的对称加密算法,并通过示例代码演示了DES算法在ECB和CBC模式下的加密和解密过程,以及如何封装DES实现CBC和ECB的PKCS7Padding分块填充。
12 4
2023/11/10学习记录-C/C++对称分组加密DES
|
4月前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
89 0
|
27天前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
70 5
|
2月前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
|
2月前
|
编译器 C语言 C++
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
24 1
|
2月前
|
Java 编译器 C++
c++学习,和友元函数
本文讨论了C++中的友元函数、继承规则、运算符重载以及内存管理的重要性,并提到了指针在C++中的强大功能和使用时需要注意的问题。
27 1
|
2月前
|
C++
【C++】深入探索类和对象:初始化列表及其static成员与友元(二)
【C++】深入探索类和对象:初始化列表及其static成员与友元
|
2月前
|
编译器 C++
【C++】深入探索类和对象:初始化列表及其static成员与友元(三)
【C++】深入探索类和对象:初始化列表及其static成员与友元
|
2月前
|
C++
C++入门4——类与对象3-2(构造函数的类型转换和友元详解)
C++入门4——类与对象3-2(构造函数的类型转换和友元详解)
26 0