【C++】从入门到精通第三弹——友元函数与静态类成员

这里写目录标题

静态类成员

类成员一般都需要通过对象来访问,不可以通过类名直接访问,但是当我们将类成员定义为静态类成员,则允许使用类名直接访问。

静态类成员是在类成员前定义static关键字。

cpp 复制代码
  1 #include<iostream>
  2 using namespace std;
  3 class Cbook
  4 {
  5     public:
  6        static int price;
  7 };
  8 int Cbook::price = 410;
  9 int main()
 10 {
 11     Cbook cbook;
 12     cout<<"Cbook in"<<Cbook::price<<endl; //通过类名直接访问类成员
 13     cout<<"Cbook use"<<cbook.price<<endl;//通过对象访问静态类成员
 14 
 15 
 16     return 0;
 17 }

注意:在定义静态类成员时,通常需要在类体外部对静态类成员进行初始化。

静态类成员是被所有的类共享的,无论定义多少个类对象。类的静态类成员只有一份,同时,如果一个对象修改了静态类成员,那么其他对象的静态类成员也将改变(修改的是同一个静态类成员)

静态类成员可以是当前类的类型,其他数据类成员只能是当前类的指针或应用类型,在定义类成员时,对于静态类成员,其类型可以是当前类的类型,而非静态类·成员则不可以,除非数据成员的类型为当前类的指针或引用类型。

cpp 复制代码
  8 class CBOOK
  9 {
 10     public:
 11         static int price;
 12     //    CBOOK cbook;错误,非法定义
 13         static CBOOK cook;
 14         CBOOK *cbook;
 15 };

静态类成员可以作为成员函数的默认参数,在定义类的成员函数时,可以为成员函数指定默认参数,其参数的默认值也可以是类的静态类成员,但是不同的数据成员不能作为成员函数的默认参数。

类的静态成员函数只能访问类的静态成员,而不能访问普通的数据成员。

而且静态类成员函数不能定义为const成员函数,如果函数的实现代码位于类体之外,则在函数的实现部分不能再标识static关键字。

友元

友元概述

友元是使用friend关键字, 让特定的函数或者别的类的所有成员函数对私有数据成员进行读写。

好处是:可以保持数据的私有性,又可以让特定的类或者函数直接访问私有成员。

为了提升效率,友元可以让普通函数直接访问一个类的保护或私有数据成员,但是如果没有友元机制,就只能将类的数据成员声明为公共的,从而任何函数都可以无约束地访问它。

友元函数:

cpp 复制代码
1 #include<iostream>
  2 using namespace std;
  3 class Friendfunction
  4 {   
  5     public:
  6         Friendfunction()
  7         {
  8             m_height = 0;
  9             m_width = 0;
 10         }
 11         Friendfunction(int height,int width)
 12         {
 13          m_width = width;
 14          m_height = height;
 15         }
 16         int getHeight()
 17         {
 18             return m_height;
 19         }
 20         int getWidth()
 21         {
 22             return m_width;
 23         }
 24         friend int friendfunction(Friendfunction &myret);
 25         protected:
 26         int m_height;
 27         int m_width;
 28 };
 29 int friendfunction(Friendfunction &myret)
 30 {
 31     return myret.m_height*myret.m_width;
 32 }
 33 int main()
 34 {
 35     Friendfunction ff(120,210);
 36     cout<<"result = "<<friendfunction(ff)<<endl;
 37 
 38     return 0;
 39 }

在函数friendfunction中可以直接使用Friendfunction类对象中的数据成员,就是因为第24行代码的作用:

cpp 复制代码
 24         friend int friendfunction(Friendfunction &myret);

此例子既很好的保护隐藏了数据,又可以使外界的特定函数直接访问这些隐藏数据。

接下来介绍友元类

就如下面第14行代码所示 : friend class Clist; 就可以声明友元类啦。用法和功能与友元函数用法功能类似。这里就不再详细赘述了,直接看代码:

cpp 复制代码
  1 #include<iostream>
  2 #include<string>
  3 using namespace std;
  4 class Cltem
  5 {
  6     private:
  7         string m_name;
  8         void outputname()
  9         {
 10             cout<<"name = "<<m_name<<endl;
 11             
 12         }
 13     public:
 14        friend class Clist;
 15         void setltemname(string name)
 16         {
 17            m_name= name;
 18         }  
 19 };      
 20 class Clist
 21 {
 22     private:
 23         Cltem m_ltem;
 24     public:
 25         void outoutltem();
 26 };
 27 void Clist::outoutltem()
 28 {
 29     m_ltem.setltemname("beijing");
 30     m_ltem.outputname();
 31 }
 32 int main()
 33 {
 34     Clist list;
 35     list.outoutltem();
 36 
 37     return 0;
 38 }

定义Cltem类时,使用了friend关键字将Clist类定义为Cltem类 的友元,这样一来,Clist类中的所有方法都可以访问Cltem类中的私有成员了。

友元方法

在我们真正开发程序时,有时候需要控制一个类对当前类的私有成员的发法。比如,我们需要实现只允许Cbook类中的某个成员来访问·Clibrary类的私有成员,而不允许其他成员函数访问Clibrary类的私有数据,这可以通过定义友元函数来实现。在定义Clibrary类的时候,可以将Cbook类的某个方法定义为友元方法,这样就限制了只有该方法允许访问Clibrary类的私有成员。

cpp 复制代码
1 #include<iostream>
  2 using namespace std;
  3 class Clibrary;
  4 class Cbook
  5 {
  6     public:
  7         Cbook();
  8         ~Cbook();
  9         Clibrary *position;
 10         void putcbook(); //声明友元
 11         //void notfriendcbook();//不声明友元,作为对比
 12 };
 13 class Clibrary
 14 {
 15     friend void Cbook::putcbook();
 16     private:
 17     string name;
 18     void putname()
 19     {
 20         cout<<"name = "<<name<<endl;
 21     }
 22     public:
 23     void setname(string name);
 24 };
 25 void Clibrary::setname(string name)
26 {   
 27     this->name = name;
 28 }
 29 void Cbook::putcbook()
 30 {   
 31     position->setname("beijing");
 32     position->putname();
 33 }  /*
 34 void Cbook::notfriendcbook()
 35 {
 36     position->setname("beijing");
 37     position->putname();
 38 }*/
 39 Cbook::Cbook()
 40 {
 41     position = new Clibrary();
 42 }
 43 Cbook::~Cbook()
 44 {
 45     delete position;
 46    position = NULL;
 47 }
 48 
 49 int main()
 50 {
 51     Cbook cook;
 52     cook.putcbook();
 53 
 54    // cook.notfriendcbook();
 55     return 0;
 56 }

就像上面代码所示,如果把没有声明友元的成员函数放开,就会出现下面这样的错误。

bash 复制代码
[bsk@localhost c++]$ g++ friendmethod.cpp 
friendmethod.cpp: In member function 'void Cbook::notfriendcbook()':
friendmethod.cpp:18:10: error: 'void Clibrary::putname()' is private
     void putname()
          ^
friendmethod.cpp:37:23: error: within this context
     position->putname();

原因也很简单,就是因为notfriendcbook()成员函数不是Clibrary类的友元,所以这个成员函数就不能访问去访问Clibrary类中的私有属性。

此外,全局函数也可以作为类友元,一样可以访问类中的私有成员。

最后简单来谈一下

友元函数在访问类对象中的成员时,不需要通过对象名。友元函数没有this指针,如果不通过对象名就无法找到类对象中的非static成员,也就无法访问。但是当访问类对象中的static成员时,就可以不用通过对象名访问。

相关推荐
蒟蒻的贤42 分钟前
vue11.22
开发语言·前端·javascript
程序员与背包客_CoderZ1 小时前
C++设计模式——Abstract Factory Pattern抽象工厂模式
c语言·开发语言·c++·设计模式·抽象工厂模式
Mike_188702783511 小时前
深入探索Golang的GMP调度机制:源码解析与实现原理
开发语言·后端·golang
SoraLuna1 小时前
「Mac玩转仓颉内测版32」基础篇12 - Cangjie中的变量操作与类型管理
开发语言·算法·macos·cangjie
2402_839708051 小时前
第十章:作业
开发语言·前端·javascript
东方巴黎~Sunsiny1 小时前
给定数字 [3, 30, 34, 5, 9] 拼接成的最大数字,使用java实现
java·开发语言
焦糖酒1 小时前
JS精进之Hoisting(提升)
开发语言·前端·javascript
daiyang123...1 小时前
Java 复习 【知识改变命运】第九章
java·开发语言·算法
fancc椰1 小时前
C++基础入门篇
开发语言·c++
不7夜宵2 小时前
Golang 反射
开发语言·后端·golang