`
BlogDown
  • 浏览: 213745 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

C++重要性质2!

 
阅读更多

1、你一定想知道虚函数是怎么做出来的,对不对?

      如果能够了解 C++编译器 对于 虚函数 的实现方式,我们就能够知道为什么虚函数可以做到动态绑定。为了达到动态绑定的目的,C++编译器通过某个表格,在执行期“间接”调用实际上欲绑定的函数。这样的表格称为 虚函数表(vtable)。每一个内含虚函数的类,编译器都会为它做出一个虚函数表,表中的每一个元素都指向一个虚函数的地址。此外,编译器也会为类的对象加上一项成员变量,是一个指向该虚函数表的指针(vptr)。举个例子:

 

  1. class class1  
  2. {  
  3. public:  
  4.       int data1;  
  5.       int data2;  
  6.       memfunc();  
  7.       virtual vfunc1();  
  8.       virtual vfunc2();  
  9.       virtual vfunc3();  
  10. };  
 

 

class1对象在内存中占据的空间为:一个虚表指针、2个整数。C++类的成员函数(非虚函数),你可以想象成就是C语言中的函数,他只是被编译器改过名称,并增加一个参数(this指针),因而可以处理调用者(C++对象)中的成员变量。所以,在class1对象的内存中并没有看到与成员函数有关的任何东西。

      每一个由此类派生出来的对象,都有这么一个vptr。当我们通过这个对象调用虚函数时,事实上就是通过vptr找到虚函数表,再找出虚函数的真正地址。虚函数表的内容是依据类中虚函数的声明次序,一一填入函数指针。派生类会继承基类的虚函数表(以及所有其它可以继承的成员),当我们在派生类中改写虚函数时,虚函数表就受了影响:表中元素所指的函数地址将不再是基类的函数地址,而是派生类的函数地址。动态绑定机制,在执行期,根据虚函数表,做出了正确的选择。

2、静态成员(变量与函数)

      我想你已经很清楚了,如果你依据一个类产生出3个对象,每个对象将各有一份成员变量。假设你有一个类,专门用来处理存款账户,它至少要有存户的姓名、地址、存款额、利率等成员变量:

 

  1. class SavingAccount  
  2. {  
  3. private:  
  4.       char m_name[40];//存户姓名  
  5.       char m_addr[60];//存户地址  
  6.       double m_total;//存款额  
  7.       double m_rate;//利率  
  8. };  
 

 

      这家银行采用浮动利率,每个账户的利息都是根据当天的挂牌利率来计算。这时候m_rate就不适合成为每个账户对象中的一笔数据,否则每天一开市,光把所有账户内容叫出来,修改m_rate的值,就花掉不少时间。m_rate应该独立在各对象之外,成为类的数据。怎么做,在m_rate前加上static修饰词即可。

      static成员变量不属于对象的一部分,而是类的一部分,所以程序可以在 还没有诞生任何对象的时候 就处理此种成员变量。但首先你必须初始化它。不要把static成员变量的初始化安排在类的构造函数中,因为构造函数可能一再被调用,而变量的初值却只应该设定一次。也不要把初始化操作安排在头文件中,因为它会被载入许多地方,因此也就可能被执行许多次。你应该在应用程序文件中,类以外的任何位置设定其初值。例如在main中,或全局函数中,或任何函数之外:double SavingAccount::m_rate = 0.0075;//设定static成员变量初值(定义,类中只是声明),这么做可曾考虑到m_rate是个private数据,没关系,设定static成员变量初值时,不受任何存取权限的束缚。请注意:static成员变量的类型也出现在初值设定语句中,因为这是一个设定操作,不是一个赋值操作。事实上,static在这时候才被定义出来,在类中只是声明了一下。如果你没有做这个初始化操作,会产生链接错误。

      下面是几种存取static成员变量的方式,注意:此时,还没有诞生任何对象实例:

1、SavingAccount::m_rate=0.0075;   2、SavingAccount myAccount;  myAccount.m_rate=0.0075;//m_rate需为public

你要搞清楚一个概念,static成员变量不是因为对象的实现才得以实现,它本来就存在,你可以想象他是一个全局变量,因此,第一种处理方式在意义上比较不会给人错误的印象。只要access level允许,任何函数(包括全局函数或成员函数,static 或 non-static)都可以存取static成员变量。但如果你希望在产生任何object对象之前就存取其class的private static成员变量,则必须设计一个static成员函数。

      由于static成员函数不需要借助任何对象,就可以被调用执行,所以编译器不会为它暗加一个this指针。也因为如此,static成员函数无法处理类中的non-static成员变量。还记得吗?前面说过,成员函数之所以能够以一份单一函数代码处理各个对象的数据而不紊乱,完全靠的是this指针的指示。

      static成员函数没有this参数的这种性质,正是我们的MFC应用程序在准备callback函数时所需要的。

3、C++程序的生与死:兼谈构造函数与析构函数

      C++的new运算符 和 C的malloc函数都是用于配置内存,但前者比之后者的优点是,new不但配置对象所需的内存空间,同时会引发构造函数的执行。

      所谓构造函数,就是对象诞生后第一个执行(并且是自动执行)的函数,它的函数名称必定要与类名称相同。相对于构造函数,自然就有个析构函数,也就是在对象行将毁灭但未毁灭之前一刻,最后(并且是自动执行)的函数。它的函数名称必定要与类名称相同,再在最前面加一个~符号。

      一个有着层次结构的类群组,当派生类的对象诞生之前,构造函数的执行是由最基类 至 最尾端派生类;当对象要毁灭之前,析构函数的执行则是反其道而行。

结论:

1)对于全局对象,程序一开始,其构造函数就先被执行(比程序进入点更早);程序即将结束前其析构函数被执行。MFC程序就有这样一个全局对象,通常以application object称呼之。

2)对于局部对象,当对象诞生时,其构造函数被执行;当程序流程将离开该对象的存活范围时,其析构函数被执行。

3)对于静态(static)对象,当其对象诞生时其构造函数被执行;当程序将结束时,其析构函数被执行,但比全局对象的析构函数早一步执行。

4)对于以new方式产生出来的局部对象,当对象诞生时其构造函数被执行,析构函数则在对象被delete时执行。

4、四种不同的对象生存方式(stack-堆栈、heap-堆、global-全局对象、static-静态对象)

      既然谈到了static对象,就顺便说一下所有可能的对象生存方式 及其 构造函数调用机制。在C++中,有四种方法可以产生一个对象,

第一种方法:是在堆栈(stack)中产生它:void MyFoo(){CFoo foo;//在堆栈中产生foo对象}

第二种方法:是在堆中产生它:void Myfoo(){CFoo* pFoo=new CFoo();//在堆中产生对象}

第三种方法:产生一个全局对象(同时也必然是个静态对象)CFoo foo;//在任何函数范围之外做次操作

第四种方法:产生一个静态局部对象void MyFoo(){static CFoo foo;}//在函数范围之内的一个静态对象

不论那一种做法,C++都会产生一个针对CFoo构造函数的调用操作。前2种情况,C++在配置内存之后,立刻产生一个隐藏的构造函数调用。第三种情况,由于对象实现于任何“函数活动范围”之外,显然没有地方来安置这样一个构造函数调用操作,这就需要startup代码帮忙,startup代码是什么?是更早于程序进入点执行起来的代码,由C++编译器提供,被链接到你的程序中。startup代码可能做些像函数库初始化、进程信息设立、I/Ostream产生等操作,以及对static对象的初始化操作。

分享到:
评论

相关推荐

    C++的学习方法及书籍推荐

    在此我把C++最重要的性质写下来:C++是一门静态类型检查,基于C内存模式,支持四种基本程序设计范型的语言。注意,这里说明了三个本质特性,静态说明了语言的类型检查性质,基于C内存模式告诉我们在C++中所有与内存...

    C++标准库介绍.pdf

    标准c库大全:C++标准库介绍 疯狂代码 http://CrazyCoder.cn/ ĵ:http:/CrazyCoder.cn/VC/Article12860.html  标准库中提供了C基本设施虽然C标准库随着C标准折腾了许多年直到标准出台才正式定型但是在标准库实 现上...

    谭浩强C语言程序设计,C++程序设计,严蔚敏数据结构,高一凡数据结构算法分析与实现.rar

    许多人认为他开创了计算机书籍贴近大众的新风,为我国的计算机普及事业做出了重要的贡献。 谭浩强教授曾获全国高校教学成果国家级奖、国家科技进步奖,以及北京市政府授予的“有突出贡献专家”称号。《计算机世界》...

    在c/c++中把密码变星号

    其中最后一步最重要啊,因为那个getch();函数的特别性质。

    基于C++实现绘制已知函数的图像功能【100010824】

    本项目旨在绘制函数图像是帮助我们理解函数性质的重要手段。让我们使用C/C++ 语言,编写一个 MyPlot 工具,实现绘制已知函数的图像的功能,

    斐波那契数列c++.pdf

    它的前几项为:1、1、2、3、5、8、13、21、34……等。斐波那契数列在数学上具有许多独特的性质和特点,与黄金分割有着密不可分的联系。当数列的项数趋向于无穷大时,前一项与后一项的比值越来越逼近黄金分割值0.618...

    深入浅出 MFC 侯俊杰 rar2

    第2章 C++的重要性质 第3章 MFC六大关键技术之仿真 第4章 Visual C++集成开发环境 第5章 总观Application Framework 第6章 MFC程序的生死因果 第7章 简单而完整:MFC骨干程序 第8章 Document-View 深入探讨 第9章 ...

    MFC学习笔记

    深入浅出MFC学习笔记,涉入c++重要性质及六大关键技术。

    谭浩强C语言程序设计,C++程序设计,严蔚敏数据结构,高一凡数据结构算法分析与实现.rar )

    许多人认为他开创了计算机书籍贴近大众的新风,为我国的计算机普及事业做出了重要的贡献。 谭浩强教授曾获全国高校教学成果国家级奖、国家科技进步奖,以及北京市政府授予的“有突出贡献专家”称号。《计算机世界》...

    C++ 头文件系列(set)详解

    set如果翻译成中文应该是集合的意思,这里更确切的说是 唯一有序集合 ,性质与map类似: 关联性 元素唯一性 动态增长 有序性 此外的一个重要特点是: Key与Value是同一个对象(自映射) set == map 定义使用set...

    深入浅出 MFC (第二版) 高清晰

    第二章 C++的重要性质 第三章 MFC六大关键技术之仿真 第二篇 欲善工事先利其器 第四章 Visual C++ 集成开发环境 第三篇 浅出MFC程序设计 第五章 总观Application Framework 第六章 MFC程序的生死因果 第七章 简单而...

    深入浅出MFC

    第2章 c++的重要性质 第3章 mfc六大关键技术之仿真 第二篇 欲善工事先利其器 第4章 visual c++集成开发环境 第三篇 浅出mfc程序设计 第5章 总观application framework 第6章 mfc程序的生死因果 第7章 ...

    杨辉三角形

    一个简单的杨辉三角形,经过修改,适用大概50的杨辉三角形。 不喜勿喷。

    深入浅出MFC(第二版).rar

    深入浅出MFC(第二版) 内容提要 Win32程序基本观念 C++重要性质 MFC六大关键技术之模拟 VisualC++整合性软件开发环境

    杨辉三角代码.cpp

    它的一个重要性质是:三角形中的每个数字等于它两肩上的数字相加。   下面给出了杨辉三角形的前4行:   1   1 1   1 2 1   1 3 3 1   给出n,输出它的前n行。 输入格式 输入包含一个数n。 输出格式...

    深入浅出MFC第二版

    侯俊杰(1961年9月28日-),笔名侯捷...第二章 C++的重要性质 第三章 MFC六大关键技术之仿真 第二篇 欲善工事先利其器 第四章 Visual C++ 集成开发环境 第三篇 浅出MFC程序设计 第五章 总观Application Framework ....

    虚函数与多态,通过案例来阐述多态的概念和虚函数的使用

    本文通过案例来阐述多态的概念和虚函数的使用,这是c++的重要性质之一,是面向对象概念的重要部分。

    深入浅出MFC-简体版(2)PDF

    第2章 C++的重要性质 类及其成员——谈封装(encapsulation) 基类与派生类:谈继承(Inheritance) this指针 虚拟函数与多态(Polymorphism) 类与对象大解剖 Object slicing与虚拟函数 静态成员(变量与函数) C++...

    《深入浅出MFC (第二版)》(候捷 著)

    第二章 C++的重要性质 第三章 MFC六大关键技术之仿真 第二篇 欲善工事先利其器 第四章 Visual C++ 集成开发环境 第三篇 浅出MFC程序设计 第五章 总观Application Framework 第六章 MFC程序的生死因果 第七章 简单而...

Global site tag (gtag.js) - Google Analytics