网站正在建设维护中,如何设计企业官网,小程序商城免费,南京宜电的网站谁做的文章目录#x1f490;专栏导读#x1f490;文章导读#x1f337;友元#x1f33a;概念#x1f33a;友元函数#x1f341;友元函数的重要性质#x1f33a;友元类#x1f341;友元类的重要性质#x1f337;内部类#xff08;不常用#xff09;#x1f33a;内部类的性… 文章目录专栏导读文章导读友元概念友元函数友元函数的重要性质友元类友元类的重要性质内部类不常用内部类的性质匿名对象关于拷贝对象时一些编译器优化专栏导读 作者简介花想云在读本科生一枚致力于 C/C、Linux 学习。 本文收录于 C系列本专栏主要内容为 C 初阶、C 进阶、STL 详解等专为大学生打造全套 C 学习教程持续更新 相关专栏推荐C语言初阶系列 、C语言进阶系列 、数据结构与算法 文章导读
本文为类和对象终章我们将学习友元的概念包含友元函数和友元类内部类匿名对象以及关于拷贝构造时一些编译器优化的情况等。
友元
面向对象有三大特性——封装、继承、多态。从学习C至今我们一直在谈封装的重要性。但是在某些特殊的情况下有时需要突破封装的限制。
举例
之前我们通过实现日期类来学习运算符重载。其中实现操作符流插入、流提取的重载时我们遇到了难题——如果在类中实现重载我们无法调换this指针的位置导致实现出来的重载用起来怪怪的。如下
class Date
{
//...//使用因为返回为了适应连续输入或输出的情况ostream operator(ostream out){out _year 年 _month 月 _day 日 endl;return out;}istream operator(istream in){in _year _month _day;return in;}//...
}
void Test()
{Date d1(2023, 4, 1);d1 cout;//有点奇怪
}还记得当时我们是怎么解决的吗答案是可以将两个函数改为友元函数。例如
class Date
{
//...//声明友元函数friend ostream operator(ostream out, const Date d);friend istream operator(istream in, Date d);//...
}
ostream operator(ostream out, const Date d)
{out d._year 年 d._month 月 d._day 日;return out;
}istream operator(istream in, Date d)
{in d._year d._month d._day;return in;
}上次我们只是浅浅的看了一下友元函数的使用。今天我们正式认识一下友元。
概念
友元提供了一种突破封装的方式有时提供了便利。但是友元会增加耦合度破坏了封装所以友元不宜多用。
友元分为友元函数和友元类。
友元函数
友元函数可以直接访问类的私有成员它是定义在类外部的普通函数不属于任何类但需要在类的内部声明声明时需要加friend关键字。
示例
{
//...//声明友元函数friend ostream operator(ostream out, const Date d);friend istream operator(istream in, Date d);//...
}
ostream operator(ostream out, const Date d)
{out d._year 年 d._month 月 d._day 日;return out;
}istream operator(istream in, Date d)
{in d._year d._month d._day;return in;
}友元函数的重要性质
友元函数有如下几条重要的性质
友元函数可访问类的私有和保护成员但它不是类的成员函数友元函数不能用const修饰友元函数可以在类定义的任何地方声明不受类访问限定符限制一个函数可以是多个类的友元函数友元函数的调用与普通函数的调用原理相同
友元类
友元类的所有成员函数都可以是另一个类的友元函数都可以访问另一个类中的非公有成员。
示例
class Time
{friend class Date;//声明日期类为时间类的友元类则在日期类中可以直接发访问时间类Time(int hour 0, int minute 0, int second 0): _hour(hour), _minute(minute), _second(second){}
private:int _hour;int _minute;int _second;
};
class Date
{
public:Date(int year 2023, int month 4, int day 9): _year(year), _month(month), _day(day){}void SetTime(int hour, int minute, int second){// 直接访问时间类私有的成员变量_t._hour hour;_t._minute minute;_t._second second;}
private:int _year;int _month;int _day;Time _t;
};友元类的重要性质
友元类的重要性质如下
友元关系是单向的不具有交换性。
比如上述Time类和Date类在Time类中声明Date类为其友元类那么可以在Date类中直接访问Time类的私有成员变量但想在Time类中访问Date类中私有的成员变量则不行。
友元关系不能传递
如果C是B的友元 B是A的友元则不能说明C是A的友元。
友元关系不能继承先不做解释
内部类不常用
如果一个类定义在另一个类的内部这个类就叫做内部类。内部类是一个独立的类它不属于外部类更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。
内部类有一个重要的性质——内部类天生就是外部类的友元。参照友元类的定义内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
内部类的性质
内部类可以定义在外部类的public、protected、private下。注意内部类可以直接访问外部类中的static成员不需要外部类的对象或类名。sizeof(外部类)外部类说明外部类和内部类在空间上没有任何关系。
示例
class A
{
private://声明static成员static int k;int n0;
public:class B // B天生就是A的友元{public:void print(const A a){cout k endl;cout a.n endl;}};
};//初始化static成员
int A::k 1;int main()
{A::B b;//定义B类对象A a;b.print(a);return 0;
}匿名对象
匿名对象顾名思义该对象没有名字就叫匿名对象。匿名对象重要的性质
匿名对象的生命周期只在定义它的那一行
示例
class A
{
public:A(int a 0):_a(a){}
private:int _a;
};int main()
{//普通对象A a1;//匿名对象的定义return 0;
}匿名对象看似鸡肋但在某些场合下非常适用。比如我们只想拿到类内部的某个成员的值或只是想用一下类中的某个成员函数为了一件简单的事而专门定义一个对象再销毁显得有点多此一举那么就可以使用匿名对象。
示例
class solution
{
public:int Sum_Solution(int n){int sum 0;for (int i 1; i n; i){sum i;}return sum;}
};
int main()
{//匿名对象的使用场景cout solution().Sum_Solution(100) endl;return 0;
}关于拷贝对象时一些编译器优化
对于有些场景下若出现拷贝构造与构造同时出现的情况编译器可能省略中间的拷贝构造转化为直接构造。此种情况取决于不同编译器不同的实现方法
示例
上一章中我们谈到类型转换。这是典型的1个拷贝构造1个构造优化为——直接构造。
class Date
{
public:Date(int year):_year(year){}
private:int _year0;
};void Test()
{//1个拷贝构造1个构造优化为——直接构造Date d2 2023;
}其它情况
class A
{
public:A(int a 0):_a(a){}
private:int _a;
};void func1(A aa)
{}void func2(const A aa)
{}A func3()
{A aa;return aa;
}A func4()
{return A();
}int main()
{A aa1 1; // 构造拷贝构造 —— 优化为直接构造func1(aa1); // 无优化func1(2); // 构造拷贝构造 —— 优化为直接构造func1(A(3)); // 构造拷贝构造—— 优化为直接构造func2(aa1); // 无优化func2(2); // 无优化func2(A(3)); // 无优化A aa1 func3(); // 拷贝构造拷贝构造 -- 优化为一个拷贝构造A aa2;aa2 func3(); // 不能优化func4(); // 构造拷贝构造 -- 优化为直接构造A aa3 func4(); // 构造拷贝构造拷贝构造 -- 优化为直接构造return 0;
}点击下方个人名片可添加博主的个人QQ交流会更方便哦~ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓