我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C++的友元和虚函数是什么

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C++的友元和虚函数是什么

这篇文章主要介绍了C++的友元和虚函数是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++的友元和虚函数是什么文章都会有所收获,下面我们一起来看看吧。

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类。虚函数必须是基类的非静态成员函数,其访问权限可以是protected或public。

几点基本知识:

如果类A是类B的友元,则类A(的成员函数)可以直接访问类B的私有成员。

友元不能继承。也就是说,类A是类B的友元,类D是类B的派生类,则类A并不会直接是类D的友元。通俗一点,父亲的朋友,并不天生就是儿子的朋友。

虚函数的基本知识就不说了。

来看下面的几段代码:

Code:

class A;  class B  {  private:  virtual void output()  {  cout << "B::output" << endl;  }  friend class A;  };  class D : public B  {  private:  virtual void output()  {  cout << "D::output" << endl;  }  };

A 是 B 的友元类,而D是B的派生类。 所以,若想在A中直接访问D的代码,则编译不过:

Code:

class A  {  public:  void test()  {  D d;  d.output(); //编译出错  }  };

这一点大家都没觉得有问题,毕竟书上写得都明白直观:父类的友元,并不会因为继承,而成为派生类的友元。

但若代码改成这样,编译器似乎就被欺骗了:

Code:

class A  {  public:  void test()  {  D d;  B* pb = &d;  pb->output(); //编译通过  }  };

没错,很多人会认为这种代码,就算能通过编译器,也很可能是一种不好的代码,因为它怎么看都像是在欺骗编译器。是这样吗?先不讨论。先问一个问题: 上面的08行代码,output调用的是B类的那个output,还是D类的那个呢?

回答正确并不难&mdash;&mdash;既然会认定这段代码带有“欺骗”性质,而且又注意到output是一个“虚函数”的话&mdash;&mdash;就能能正确地解答: 调用的是D类的。A明明只是B的友元,但却通过一个简单的类型转换,就访问了D类的那个私有函数,所以会觉得这是一种“欺骗”。

如果这是一种欺骗,那我们先来回答这个骗局为什么能成立:因为“友元”的判断(resolve),在编译期决定;而虚函数在运行期去resolve。在编译08行代码时,编译器看到*pb的类型是B,而A是B的友元,所以允许它调用output(它认为是B::output);而在运行时,由于output是虚函数,所以最终被决定到D::output头上。

一、首先要理解为什么派生类不应该继承基类的"友元",这一点很多C++的书讲到了

二、其次要理解它的语法机制:前面讲的,一个编译期属性与一个运行期属性相遇了&hellip;&hellip;

三、要理解如果想关掉这一类欺骗,其实做不到。且来看看,该法之一是在编译期,也检查实际调用对象的类型,前面的示例代码不难做到这一点,但下面的代码中,pb来自一个形参:

Code:

A::test_2(B* pb)  {  pb->output(); //很难在编译期反查出pb的实际类型。  //因为调用test_2()的代码,可能无处不在,甚至可能在未来的代码  }

四、要理解有时候,人们其实就是在故意做这种事,最典型的做法,就是通过非虚函数调用虚函数:

Code:

class B  {  public:  void Action()  {  this->DoAction();  }  private:  virtual void DoAction() = 0; //一个私有的纯虚函数  // friend class A;  };

任何一个合格的C++程序员,都应该学会这种作法。DoAction是一个纯虚函数,这里我们更决绝一点,干脆让它是私有的,这就是逼着派生类自己去实现一个完全自我的DoAction(),假设有个class D : public B,并且听话地实现了DoAction。具体D的定义,为节省点篇幅,不写了。

注意到第11行的注释, class A 现在已经不是 B 的友员了,但不要紧,我们只是想在新版的类A中,调用Action函数,而它是public的,所以这里不需要友元来搅和。

Code:

class A  {  void test()  {  B* pb = new D; //pb 实际指向一个D对象。  pb->Action(); // Action 是 公开的,所以可以调用  }  };

pb 调用了非虚的B::Action函数,但在Action内调用了虚函数DoAction,再由于pb实际指向的是D对象,所以最终调用的是D::DoAction()&mdash;&mdash;这了无新意对不对?只要学过一点C++的多态,都会懂这一点。没错,它太司空见惯了,基本上所有C++程序员每天都会在写类似的代码&mdash;&mdash;这就是我想说的,有时候,看起来在调用基类的代码,但实际上在调用派生类的代码。假设我们修改了语法规则,逼着虚函数在遇上友元之后失效,那就是逼着程序员不去用friend,去将更多本来应该是private的成员,用各种该法写成public的。

五、接着,是一个看起来很简单,但却被很多人误解的概念:友元是破坏了封装了吗?错,友元其实是促进了更好的封装。它基于这样的需求:有一个类,它有那么几个成员(数据或函数),它只能对个别的其它类公开,这时,你可以考虑使用友元这项技术。如果不用,会有很多人就把那些成员直接修改为public,结果:原本应只对个别类开放的属性,变成对所有类开放了。俗气一点,法律规定老婆可以在私有场合下看老公的屁屁,如果法律强制规定不允许有这种例外,那很可能会有一些哥们,直接把屁股public出来就上街了&mdash;&mdash;你若问他为什么,他也很无辜:我不过是想让我老婆方便一些。

六、读了第五点,对OO有一套的C++程序员要“笔试/鄙视”我了,好,好,我知道既使不用friend的属性,也可以美满地实现前述的,类似老婆看老公屁股的问题&mdash;&mdash;我是说,通过OO技术,避开需要只对部分类开放权限的需求,而转化为第三方(比如某个接口及它的实现类)中&mdash;&mdash;不管如何,你必须承认友元没有破坏封装性,因为其它解决这一问题的的,似乎更纯粹的OO技术,它们美好的地方是在于更细的类颗粒,以及更好的类组织(不美好地方是,效率差了点,以及对OO思想非得有点水准,否则会绕晕掉,为了不让Cer笑话,我们不提太多)。

七、不过,纵算如此(第六点),我还是是狡辩一句:就算是在那些看起来很纯的OO语言里,其实也有友元的影子啊。比如Java,是没有friend关键字,可以它的内部类(非静态的内部类),可以直接访问外部类,难道不是友元吗?&mdash;&mdash;事实上,这也正是在C++使用friend最主旋律的用法(我甚至不用写“之一”)。再如Object Pascal(Delphi),是没有friend关键字,可是只要是位于同一个代码单元(就是同一个.pas文件),则其中所有类天生就是可以互相访问啊(当然,需首先满足可见性)&mdash;&mdash;这是当年我用Delphi时觉得最爽的地方之一了,既然号称更OO的语言都留了一手,为何C++不能呢? :)

八、第七点明显带有情绪化,这不符合C++之父对我们的期望: “ 在C++设计中有一条指导原则,那就是,无论做什么事情,都必须相信程序员。与可能出现什么样的错误相比,更重要得多的是能做出什么好事情。C++程序员总被看作是成年人&hellip;&hellip;” 。在C++的大千世界,差异性永远被尊重, 有人不爱用template,那不用就是; 有人坚决认为只要有private和public就足够了,那就把protected忘记吧,甚至有人认为virtual也是多余的&mdash;&mdash;很多人就是把C++当成另一种C使用,那都可以接受。friend也一样,如果你不用,它的存在并不会给你带来什么性能损失,你要做的就是用很OO或很不OO的,但是你熟悉的方法去满足友元的需求而已。

九、一定要这个第9点。 除了友元类,更常见的其实是友元函数。很多操作符的重载,都需要全局的友元函数来减轻相关类的public出太多成员。这一下扯到“操作符重载”有用吗?哇,这是另外一个经典的问题了,它曾经引起的纠纷,比这个“友元”所带来的,要热闹上几倍呢。就此打住。

十、***一点,C++初学者如何学习这门语言众多的,又容易产生正交效应的特性呢?我有个建议:先有个基本了解,做点练习,但并不需要急着真正使用。

友元的作用是提高了程序的运行效率,即减少了类型检查和安全性检查等都需要时间开销,但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。而虚函数的作用则是为了实现多态。

关于“C++的友元和虚函数是什么”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“C++的友元和虚函数是什么”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C++的友元和虚函数是什么

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C++的友元和虚函数是什么

这篇文章主要介绍了C++的友元和虚函数是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++的友元和虚函数是什么文章都会有所收获,下面我们一起来看看吧。友元可以是一个函数,该函数被称为友元函数;友元也可以是
2023-06-17

C++友元函数的作用是什么

C++友元函数的作用是允许一个函数访问一个类的私有成员和保护成员。通常情况下,只有类的成员函数可以访问类的私有成员和保护成员,但是有时候我们需要在类外部定义一个独立的函数来访问类的私有成员和保护成员。这时,我们可以将该函数声明为友元函数。友
2023-10-11

C++ 友元函数与虚函数的交互

在 c++++ 中,友元函数与虚函数交互使友元函数可以访问虚函数,并调用派生类中的友元函数访问基类的私有成员。这种交互可用于访问继承体系中隐藏的数据或实现多态行为。C++ 友元函数与虚函数的交互在 C++ 中,友元函数是一种能够访问类私有
C++ 友元函数与虚函数的交互
2024-04-16

C++之友元:友元函数和友元类详解

友元是一种允许非类成员函数访问类的非公有成员的一种机制。可以把一个函数指定为类的友元,也可以把整个类指定为另一个类的友元
2022-11-15

C++ 函数可以声明为友元函数吗?友元函数的特性是什么?

是的,c++++ 函数可以声明为友元函数。友元函数具有以下特性:可以访问类的私有和受保护成员。不能直接访问类的 this 指针。可以定义在类的作用域之外。不是类的成员函数,不属于类的接口。C++ 函数可以声明为友元函数吗?友元函数的特性是什
C++ 函数可以声明为友元函数吗?友元函数的特性是什么?
2024-04-19

C++ 友元函数详解:友元函数和函数指针的结合?

将友元函数与函数指针结合将友元函数与函数指针结合使用,提供以下好处:动态绑定,允许在运行时更改友元函数的执行。泛型编程,使友元函数能够处理不同类型的对象。C++ 友元函数详解:将友元函数与函数指针结合简介友元函数是 C++ 中一种特殊的
C++ 友元函数详解:友元函数和函数指针的结合?
2024-04-30

C++ 友元函数详解:友元函数和全局函数的区别?

友元函数可访问类私有和受保护数据成员,而全局函数不行,友元函数在类声明中声明,全局函数在类外声明,使用 friend 关键字声明友元函数,用 extern 关键字声明全局函数。友元函数通过声明方式获得访问类成员变量的权限,如通过声明一个友元
C++ 友元函数详解:友元函数和全局函数的区别?
2024-04-28

C++ 友元函数详解:友元函数和成员函数的区别?

友元函数允许外部函数访问类中的私有或受保护成员,通过在类定义中用 friend 关键字声明。与成员函数不同,友元函数声明在类外部,可访问类的私有和保护成员,而成员函数在类内部声明,可访问类所有成员。友元函数用作普通函数调用,而成员函数用类对
C++ 友元函数详解:友元函数和成员函数的区别?
2024-04-29

C++ 友元函数详解:友元函数的优点和缺点?

友元函数是一种特殊函数,可以访问另一个类的私有和受保护成员,优点包括跨类访问私有数据、增强封装、提高代码可重复性。缺点则包括破坏封装、增加耦合度、降低代码可读性。C++ 友元函数详解:优势与劣势什么是友元函数?友元函数是一种特殊的函数,
C++ 友元函数详解:友元函数的优点和缺点?
2024-04-28

C++ 友元函数详解:友元函数和类模板的交互?

友元函数可访问类的私有成员,通过在类声明中使用 friend 声明。类模板允许创建通用类和友元函数,适用于不同类型数据。实战案例中,友元函数模板 printdata() 可打印任何类型 myclass 实例的私有成员 data,简化代码,提
C++ 友元函数详解:友元函数和类模板的交互?
2024-04-30

C++中任何事与友元函数和友元类

本篇文章为大家展示了C++中任何事与友元函数和友元类,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类。类具有封装和信息隐藏
2023-06-17

C++ 友元函数详解:友元函数在STL中的应用?

在 c++++ 中,友元函数是一种特殊函数,可以访问其他类的私有成员。友元函数的声明使用 friend 关键字,定义时需要注意访问权限。stl 中广泛使用友元函数,以允许容器类与算法相交互,例如 std::swap()、std::ostre
C++ 友元函数详解:友元函数在STL中的应用?
2024-04-30

C++的对象特性和友元是什么

这篇文章主要介绍了C++的对象特性和友元是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++的对象特性和友元是什么文章都会有所收获,下面我们一起来看看吧。对象特征构造函数和析构函数对象的初始化和清理也是两
2023-06-29

C++ 友元函数详解:友元函数的潜在安全隐患?

友元函数允许访问类中的私有成员,虽然便利,但同时也存在以下安全隐患:破坏封装性:友元函数可访问私有成员,破坏类的封装。交叉污染:多个类声明同一个友元函数,导致意外的数据修改或错误。C++ 友元函数详解:潜在安全隐患友元函数是一种特殊类型的
C++ 友元函数详解:友元函数的潜在安全隐患?
2024-04-30

C++中的成员函数和友元函数怎么使用

成员函数是定义在类中的函数,它可以访问类中的成员变量和其他成员函数。成员函数使用类的对象来调用,并且隐式地访问该对象的成员。友元函数是在类外部定义的函数,它可以访问类的私有成员。友元函数可以在类中声明为友元,或者在类外部声明为友元。下面是成
2023-08-16

C++友元函数怎么调用

在C++中,友元函数可以直接调用,不需要通过对象或类的实例来调用。友元函数可以在类的内部声明和定义,它可以访问类的私有成员和保护成员。以下是一个示例代码,展示了如何使用友元函数调用类的私有成员:```cpp#includeusing nam
2023-10-11

C++友元函数怎么定义和使用

C++友元函数是指一个非成员函数可以访问类的私有成员和保护成员。以下是定义和使用C++友元函数的步骤:1. 在类的声明中声明友元函数。2. 在类的定义中定义友元函数。3. 在友元函数的实现中访问类的私有成员和保护成员。下面是一个例子:```
2023-10-11

C++ 友元函数详解:友元函数在不同编译单元的使用?

友元函数允许函数访问其他类的私有成员。当友元函数和它访问的类不在同一编译单元中时,有两种场景:友元函数声明在头文件中:友元函数的声明位于类的头文件中,类的定义位于不同的源文件中,友元函数可以访问私有成员。友元函数声明在源文件中:友元函数的声
C++ 友元函数详解:友元函数在不同编译单元的使用?
2024-04-28

C++ 静态函数与友元函数有什么区别?

静态函数是类方法,只访问静态成员而不接收 this 指针;友元函数不属于类,可以访问所有成员并接收 this 指针。C++ 中静态函数与友元函数的区别静态函数属于类但并不属于任何特定的对象,也可以称为类方法。使用 static 关键字声
C++ 静态函数与友元函数有什么区别?
2024-04-17

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录