当前位置: 首页 > news >正文

第五讲:类的成员、对象成员的引用

一、 类的成员函数(成员数据、成员函数与全局函数)(成员函数的性质、定义)

1、成员函数的性质

    1、类的成员函数(简称类函数)是函数的一种,它也有返回值和函数类型,它与一般函数的区别只是:它是属于一个类的成员,出现在类体中。它可以被指定为private(私有的)、public(公用的)或protected(受保护的)。
    2、在使用类函数时,要注意调用它的权限(它能否被调用)以及它的作用域(函数能使用什么范围中的数据和函数)。成员函数可以访问本类中任何成员(包括私有的和公用的),可以引用在本作用域中有效的数据。
    3、一般的做法是将需要被外界调用的成员函数指定为public,它们是类的对外接口
    4、类的成员函数是类体中十分重要的部分。如果一个类中不包含成员函数,就等同于C语言中的结构体了,体现不出类在面向对象程序设计中的作用。

2、在类外定义成员函数

    前面看到的成员函数是在类体中定义的。也可以在类体中只写成员函数的声明,而在类的外面进行函数定义。如:

class Student
    { public:
        void display();     //公用成员函数原型声明
      private:
        int num;
        string name;
        char sex;           //以上 3行是私有数据成员
    };
void Student::display()      //在类外定义display类函数
   { cout<<"hum:"<<num<<endl;//函数体
     cout<<"name:"<<name<<endl;
     cout<<"sex:"<<sex<<endl;}
Student stud1,stud2;        //定义两个类对象

说明:
    1、但成员函数在类外定义时,必须在函数名前面加上类名,予以限定(Qualifed),“::”是作用域限定符(field qualifier)或称作用域运算符,用它声明函数是属于哪个类的。
        (a)Student::display();(b)没有“Student::”的限定、“::”如 ::display() 或 display() 
    2、类函数必须先在类体中作原型声明,然后在类外定义,也就是说类体的位置应在函数定义之前(如上面所示的那样),否则编译时会出错。
    3、在类的内部对成员函数作声明,而在类体外定义成员函数,这是程序设计的一种良好习惯。

3、inline 成员函数(类内置成员函数)

    类的成员函数也可以指定为内置(inline)函数。
    问题提出: 在类体中定义的成员函数的规模一般都很小,而系统调用函数的过程所花费的时间开销相对是比较大的。调用一个函数的时间开销远远大于小规模函数体中全部语句的执行时间。
    解决办法: 为了减少时间开销,如果在类体中定义的成员函数中不包括循环等控制结构,C++系统会自动将它们作为内置(inline)函数来处理。也就是说,在程序(对象)调用这些成员函数时,并不是真正地执行函数的调用过程(如保留返回地址等处理),而是把函数代码嵌入程序的调用点。这样可以大大减少调用成员函数的时间开销。(程序调用,不占对象物理内存)
    定义方法:C++要求对一般的内置函数要用关键字inline声明,但对类内定义的成员函数,可以省略inline,因为这些成员函数已被隐含地指定为内置函数。

例如:
class Student 
    { public:
       void display()//也可以写成: inline void display()
          { cout<<”illlm:”<<hum<<endl;
            cout<<”name:”<<name<<endl;
            cout<<”sex:”<<sex<<endl;
          }
      pnvate:
        int num;
        string name;
        char sex;
    };


    注意:如果成员函数不在类体内定义,而在类体外定义,系统并不把它默认为内置(inline)函数,调用这些成员函数的过程和调用一般函数的过程是相同的。如果想将这些成员函数指定为内置函数,应当用inline作显式声明。

例如:
class Student
    { public:
        inline void display(); //声明此成员函数为内置函数
      Private:
        int num;
        string name;
        char sex;
    }
inline void Student::display() //在类外定义display函数为内置函数
    { cout<<"num:"<<num<<endl;
      cout<<"name:"<<name<<endl;
      cout<<"SCX:"<<sex<<endl;
    }

注意:
     1、如果在类体外定义inline函数,则必须将类定义和成员函数的定义都放在同一个头文件中(或者写在同一个源文件中),否则编译时无法进行置换(将函数代码的拷贝嵌入到函数调用点)。但是这样做不利于类的接口与类的实现分离,不利于信息隐蔽。虽然程序的执行效率提高了,但从软件工程质量的角度来看,这样做并不是好的办法。
    2、只有在类外定义的成员函数规模很小而调用频率较高时,才将此成员函数指定为内置函数。

4、 成员函数的存储方式

    C++编译系统为每个对象所占用的存储空间只是该对象的数据部分所占用的存储空间,而不包括函数代码所占用的存储空间。

        
图4: 一般理解              图5:C++编译系统处理

如果声明了一个类: 
class Time
    { public:
        int hour;
        int minute;
        int sec;
        void set()
           { cin>>a>>b>>c;}
    };

可以用下面的语句来输出该类对象所占用的字节数:
        cout<<sizeof(Time)<<endl; 输出的值是12。

需要注意:
    1、虽然调用不同对象的成员函数时都是执行同一段函数代码,但是执行结果一般是不相同的。
    2、不论成员函数在类内定义还是在类外定义全局函数,函数的代码段都用同一种方式存储,即都不占用对象的存储空间。
    3、不要将成员函数的这种存储方式和inline(内置)函数的概念混淆。用inline声明的作用是在调用该函数时,将函数的代码段复制插入到函数调用点,而若不用inline声明,在调用该函数时,流程转去函数代码段的人口地址,在执行完该函数代码段后,流程返回函数调用点。inline与成员函数是否占用对象的存储空间无关。
    4、既然成员函数的代码并不放在对象的存储空间中,那么前面说的“对象studl的成员函数display”的说法是否不对呢?应当说明:常说的“某某对象的成员函数”,是从逻辑的角度而言的,而成员函数的存储方式(不存储在对象的空间内),是从物理的角度而言的,是由计算机根据优化的原则实现的,二者是不矛盾的。物理上的实现必须保证逻辑上的实现。例如某人有钱若干,可以放在家中,也可以放在银行中租用的保险箱中,虽然在物理的角度上保险箱并不在他家中,但保险箱是他租用的,这笔钱无疑是属于他的,这是从逻辑的角度而言的。同样.虽然成员函数并没有放在对象的存储空间中,但从逻辑的角度,成员函数是封装在—个对象中的,所以完全可以说“调用对象studl的成员函数display”,不会引起误解。作为程序设计人员,了解一些物理实现方面的知识是有好处的,可以加深对问题的理解。

二、对象成员的引用(包含成员函数、成员数据)

在程序中经常需要访问对象中的成员。访问对象中的成员可以有3种方法:

  1.  
    1. 通过对象名和成员运算符访问对象中的成员;
    2. 通过指向对象的指针访问对象中的成员;
    3. 通过对象的引用变量访问对象中的成员。

1、通过对象名和成员运算符访问对象中的成员

访问对象中成员的一般形式为:
        对象名.成员名(包含成员函数、成员数据)

说明:
    1、“.”是成员运算符,用来对成员进行限定,指明所访问的是哪一个对象中的成员。
    2、不能只写成员名而忽略对象名, 不应该这样写:hum=1001; //错误。这样写成为对象中的临时变量。
    3、不仅可以在类外引用对象的公用数据成员,而且还可以调用对象的公用成员函数,但同样必须指出对象名,如 studl.display()。
    4、应该注意所访问的成员是公用的(public)还是私有的(pavate)。私有数据成员,不能被外界引用。
    5、在类外只能调用公用的成员函数。显然在一个类中应当至少有一个公用的成员函数,以作为类的对外接口否则程序就无法对对象进行任何操作。

2、通过指向对象的指针访问对象中的成员

访问对象中成员的一般形式为:
        对象指针名->成员名(包含成员函数、成员数据)
  或:(*对象指针名).成员名(包含成员函数、成员数据)

例如:
class Time
    { public: //数据成员是公用的
      int hour;
      int minute; 
     };
Time t,*p     //定义对象t和指向Time类的指引变量P
P=&T           //使p指向对象t
cout<<P->hour;//输出P指向的对象中的成员hour

3、通过对象的引用来访问对象中的成员

    如果为一个对象定义了一个引用,它们是共占同一段存储单元的,实际上它们是同—个对象,只是用不同的名字表示而已。因此完全可以通过引用来访问对象中的成员,其概念和方法与通过对象名来引用对象中的成员是相同的。

例如:如果已声明了Time类,并有以下定义语句:
        Time t1;      //定义对象t1
        Time &t2=t1;  //定义Time类引用变量t2,并使之初始化为tl
        cout<<t2.hour;//输出对象t1中的成员hour
由于t2与t1共占同一段存储单元(即t2是tl的别名),因此t2.hour就是t1.hour。

转自:  http://210.44.195.12/cgyy/text/HTML/text/05.htm

相关文章:

  • Linux2.6内核--进程调度理论
  • 第六讲:类、对象的简单应用及类封装、隐蔽性
  • 第七讲:构造函数与析构函数
  • 第八讲:对象数组与指针
  • elk 日志处理的一点思路
  • 第九讲:共用数据的保护与对象的动态处理
  • rtems 4.11 IRQ (arm,beagle)
  • 第十讲:对象的赋值和复制
  • jQuery插件之ajaxFileUpload[转载]
  • 第十一讲:运算符重载与重载函数
  • Google Chrome Frame 自定义渲染方式,调用ActiveX
  • 第十二讲:重载单、双目、插入、提取运算符
  • 第十三讲:不同类型数据间的转换
  • 一)6张表
  • 第十四讲:继承与派生的概念
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • 【许晓笛】 EOS 智能合约案例解析(3)
  • bearychat的java client
  • - C#编程大幅提高OUTLOOK的邮件搜索能力!
  • codis proxy处理流程
  • CSS实用技巧干货
  • JavaScript 基础知识 - 入门篇(一)
  • JAVA多线程机制解析-volatilesynchronized
  • node.js
  • PHP 的 SAPI 是个什么东西
  • SpringBoot几种定时任务的实现方式
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 浅谈web中前端模板引擎的使用
  • 浅析微信支付:申请退款、退款回调接口、查询退款
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 阿里云API、SDK和CLI应用实践方案
  • ​卜东波研究员:高观点下的少儿计算思维
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • (2009.11版)《网络管理员考试 考前冲刺预测卷及考点解析》复习重点
  • (26)4.7 字符函数和字符串函数
  • (3)选择元素——(17)练习(Exercises)
  • (Oracle)SQL优化技巧(一):分页查询
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (附源码)基于SSM多源异构数据关联技术构建智能校园-计算机毕设 64366
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (四) 虚拟摄像头vivi体验
  • (一)Linux+Windows下安装ffmpeg
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • (转)mysql使用Navicat 导出和导入数据库
  • ***检测工具之RKHunter AIDE
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • .NET 中 GetHashCode 的哈希值有多大概率会相同(哈希碰撞)
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)
  • @angular/cli项目构建--Dynamic.Form