C++内联&友元

内联(inline)

内联变量

C++17引入了内联变量,使得变量可以在头文件中定义并在多个编译单元中使用,避免了传统的extern声明和单一cpp文件定义的限制。它的作用是方便在头文件中定义全局变量而不会引起链接错误。

// usecase1.h
inline int iSize = 100;

// usecase1.cpp
#include "usecase1.h"
void test() { std::cout << iSize << std::endl; }

// main.cpp
#include "usecase1.h"
int main() {
std::cout << iSize << std::endl;
return 0;
}

内联函数

内联函数通过inline关键字声明,建议编译器在调用时将函数的代码插入调用点,避免函数调用时的开销。使用inline并不强制编译器将其内联,这是一个非绑定(non-binding)的建议。

实现内联的方式

  1. 小函数

不仅是指这个函数代码量少,而且编译成汇编指令后也要少,代码量大或者有复杂指令的,如循环、switch等,编译器都会拒绝将其编译为内联函数。另外,析构函数一般也不建议使用内联,谁也不知道最终它会调用多少其它函数来释放资源。

  1. 惟一

    这里的惟一指的是惟一的调用点,而不是调用一次。它其实是一个理论上的可能,实际上,很少能够做到。所以这点基本可以忽略。

类内定义的函数通常自动成为内联函数:

class Temp {
public:
int amount;
void print_amount() { std::cout << amount; }
};

类外定义的成员函数则需要显示声明为inline

inline void Temp::print_amount() { std::cout << amount << std::endl; }

内联函数与宏的区别

  • :在编译前由预处理器展开,不进行类型检查,可能带来隐患和维护问题。

  • 内联函数:经过编译器的类型检查,更安全,且能够继承宏的一些优点,如减少函数调用开销。

#define mult1(a, b) a * b
inline int mult2(int a, int b) { return a * b; }

int main() {
std::cout << mult1(3 + 1, 1 + 3) << std::endl; // 宏可能导致问题
std::cout << mult2(3 + 1, 1 + 3) << std::endl; // 内联函数避免了宏展开的顺序问题
}

虽然内联函数可以减少函数调用的开销,但它会增加代码体积,尤其在多次调用时。过度使用内联可能导致缓存失效,反而影响性能。因此,内联函数通常适用于小型且高频调用的函数。

友元(friend)

友元函数

友元函数是定义在类外部的普通函数,但它需要在类的内部通过 friend 关键字进行声明。友元函数虽然不属于类的成员,但它可以访问类的私有和受保护成员。友元函数的存在主要是为了在保持类的封装性的同时,提供一定的灵活性。

友元函数的特点:

  • 可以访问私有成员:友元函数可以访问类中的私有成员(privateprotected)。

  • 声明时使用 friend 关键字:友元函数需要在类的内部用 friend 关键字声明,函数的定义则可以在类外进行。

  • 不是类的成员函数:虽然友元函数能够访问类的私有成员,但它不属于该类的成员函数,也不影响类的结构。

友元函数的常见用途:

  • 运算符重载:尤其是在重载 <<>> 这样的运算符时,由于 ostreamistream 对象通常在函数调用时位于左操作数位置,需要友元函数来实现操作。

  • 跨类访问:有时需要在非成员函数中访问类的私有成员,而不想公开这些成员给所有的外部函数。

#include <iostream>
using namespace std;

class Date {
// 声明友元函数
friend ostream& operator<<(ostream& os, const Date& d);
friend istream& operator>>(istream& is, Date& d);
private:
int _year;
int _month;
int _day;
public:
Date(int year = 1900, int month = 1, int day = 1) : _year(year), _month(month), _day(day) {}
};

// 定义友元函数,重载 << 运算符
ostream& operator<<(ostream& os, const Date& d) {
os << d._year << "-" << d._month << "-" << d._day;
return os;
}

// 定义友元函数,重载 >> 运算符
istream& operator>>(istream& is, Date& d) {
is >> d._year >> d._month >> d._day;
return is;
}

int main() {
Date d;
cin >> d; // 使用重载的 >> 运算符输入日期
cout << d << endl; // 使用重载的 << 运算符输出日期
return 0;
}

<<>> 这类运算符重载时,通常第一个操作数是 ostreamistream 对象,而不是类的实例,因此无法将运算符重载定义为成员函数。这时候可以通过友元函数来实现。

友元函数声明在类中,可以访问类的私有数据成员 _year_month_day,从而对类进行输出和输入操作。

友元类

友元类是指一个类被声明为另一个类的友元,从而可以访问该类的私有和受保护成员。友元类的所有成员函数都可以访问被友元的类的私有成员。友元类是一种更广泛的友元机制,它允许两个类紧密合作。

友元类的特点:

  • 单向访问:友元类可以访问被声明为友元的类的私有成员,但这种访问权不会自动逆转(即被声明为友元的类不能访问友元类的私有成员)。

  • 不具备传递性:如果类 A 是类 B 的友元,类 C 是类 A 的友元,这并不意味着类 C 也能访问类 B 的私有成员。

  • 友元关系不能继承:友元关系仅限于声明的类,子类不能继承父类的友元关系。

友元类的常见用途:

  • 紧密协作的类:当两个类需要紧密合作并共享数据时,友元类机制可以允许一个类访问另一个类的私有成员,而不需要公开这些成员。

  • 实现复杂逻辑:某些情况下,一个类的实现依赖于另一个类的内部数据,友元类可以帮助简化这些情况。

#include <iostream>
using namespace std;

class Time {
// 声明 Date 为友元类,允许 Date 类访问 Time 类的私有成员
friend class Date;
private:
int _hour;
int _minute;
int _second;
public:
Time(int hour = 0, int minute = 0, int second = 0) : _hour(hour), _minute(minute), _second(second) {}
};

class Date {
public:
Date(int year = 1900, int month = 1, int day = 1) : _year(year), _month(month), _day(day) {}
void SetTime(Time& t, int hour, int minute, int second) {
// Date 类可以访问 Time 类的私有成员
t._hour = hour;
t._minute = minute;
t._second = second;
}
void ShowTime(const Time& t) {
cout << "Time: " << t._hour << ":" << t._minute << ":" << t._second << endl;
}
private:
int _year;
int _month;
int _day;
};

int main() {
Time t;
Date d;
d.SetTime(t, 12, 30, 45); // 通过 Date 修改 Time 的私有成员
d.ShowTime(t); // 通过 Date 输出 Time 的私有成员
return 0;
}

Time 类将 Date 类声明为友元类,因此 Date 可以访问 Time 的私有成员 _hour_minute_second

SetTime 函数通过 Date 类修改了 Time 类的私有数据,ShowTime 函数则显示了这些私有数据。

Reference

[1] C++之内联(inline):https://blog.csdn.net/haokan123456789/article/details/138469420

[2] 【C++】友元函数和友元类(作用及优缺点):https://blog.csdn.net/Jacky_Feng/article/details/109533248

------------------------------- 本文结束啦❤感谢您阅读-------------------------------
赞赏一杯咖啡