7第七讲——名空间和RTTI
- 格式:ppt
- 大小:501.00 KB
- 文档页数:72
RTTI的介绍和使⽤RTTI介绍及使⽤什么是RTTI?RTTI是[运⾏阶段类型识别](Runtime Type Identification) 。
RTTI旨在为程序在运⾏阶段确定对象的类型提供⼀种标准的⽅式。
很多类库已经为其对象提供了实现这种功能的⽅式,但由于c++内部不⽀持,因此各个⼚商的机制通常互不兼容。
RTTI的⽤途为何需要知道类型。
可能希望调⽤类⽅法的正确版本,在这种情况下,只要该函数是类层次结构中所有成员都有的虚函数,则并不真正需要知道对象的类型。
但派⽣对象可能包含不是继承⽽来的⽅法,在这种情况下,只有某些类型的对象可以使⽤该⽅法。
也可能是出于调试的⽬的,想跟踪⽣成的对象的类型。
对于后两种情况,RTTI提供解决⽅案。
RTTI的⼯作原理C++有3个⽀持RTTI的元素。
如果可能的话,dynamic_cast 运算符将使⽤⼀个指向基类的指针来⽣成⼀个指向派⽣类的指针:否则,该运算符将返回0——空指针。
typeid 运算符返回⼀个指出对象的类型的值。
type_info 结构存储了有关特定类型的信息。
警告:RTTI只适⽤于包含虚函数的类1.dynamic_cast 运算符dynamic_cast 不能回答“指针指向的是哪类对象”这样的问题,但能回答“是否可以安全地将对象的地址赋给特定的指针”这样的问题。
#include "stdafx.h"#include <iostream>#include <cstdlib>#include <ctime>using std::cout;class Grand{private:int hold;public:Grand(int h = 0):hold(h){}virtual void Speak() const { cout << "I am a grand class!\n"; }virtual int value() const { return hold; }};class Superb :public Grand{public:Superb(int h = 0) :Grand(h){}void Speak() const { cout << "I am a Superb class!\n"; }virtual void Say() const { cout << "I hold the superb value of " << value() << "!\n"; }};class Magnificent :public Superb{private:char ch;public:Magnificent(int h = 0, char c = 'A') :Superb(h), ch(c) {}void Speak() const { cout << "I am a magnificent class !\n"; }void Say() const { cout << "I hold the character " << ch << " and the integer " << value() << "!\n"; }};Grand *GetOne();Grand *GetOne(){Grand *p = nullptr;switch (std::rand() % 3){case 0:p = new Grand(std::rand() % 100);break;case 1:p = new Superb(std::rand() % 100);break;case 2:p = new Magnificent(std::rand() % 100, 'A' + std::rand() % 26);break;default:break;}return p;}int _tmain(int argc, _TCHAR* argv[]){std::srand(std::time(0));Grand *pg;Superb *ps;for (int i = 0; i < 5; i++){pg = GetOne();pg->Speak();if (ps = dynamic_cast<Superb *>(pg))ps->Say();}return 0;}2.typeid 运算符和type_info类typeid 运算符使得能够确定两个对象是否为同种类型。
Thinking in C++1.private与protect关键字的区别。
子类能访问基类的protect成员而不能访问private成员。
2.友元,friend如何声明一个友元。
3.缺省构造函数。
当类声明了一个带参数的构造函数后而没有声明无参数构造函数,编译器还会为它生成一个默认的缺省构造函数吗?分析下例的错误:class A{public:A(int i){cout<<i<<endl;}};void main(){A a;}4.构造函数有没有返回值?析构函数有没有返回值?析构函数可不可以带参数?5.解释一下重载函数重载允许两个或更多个函数使用同一个名字限制条件是它们的参数表必须不同参数类型不同或参数的数目不同。
6.重载函数如何来区分彼此?7.解释缺省参数函数8.下例能编译通过吗?为什么。
重载的缺省参数函数不能与其它函数产生二义。
void s(int i){cout<<i<<endl;}void s(int i, int j=0){cout<<i<<endl;}void main(){s(5);}9.能否用返回值来区分重载函数?10.看下例回答以下问题:a.常量必须初始化,下面的代码又和问题:const int i;i=20;b.常量有没有存储控件,或者只是编译时的符号而已?不一定c.常量一定是在编译时就确定其值的吗?const int i=100;const int j=i+100;long address=(long)&j;//强迫编译器为常量分配存储空间char buf[j+10];void main(){const char c=cin.get();const char c2=c-'a'+'A';cout<<c<<" "<<c2<<endl;}11.看下例回答以下问题:a.能否将一个非常量对象的地址赋给一个常量指针?b.能否将一个常量对象的抵制赋给一个非常量指针?若确要如此,该如何做?void main(){const int i=5;int *j=const_cast<int *>(&i);}const int* x;//常量指针int* const x=&d; //指针常量int const* x; //常量指针const int* const x=&d; //常量指针常量12.函数调用中值传递使用常量定义无甚意义:void f(const int i);但函数返回值的常量定义有特殊作用,看下例:class X{int i;public:void modify(){cout<<"haha"<<endl;}};const X fun(){return X();}void main(){//! fun().modify(); 常量不能为左值,所以下例也不成立://! const X g;//! g.modify();//!!! 常量一定不能为左值吗?看16题}13.常量的典型应用:void u(const int* p);const char* v();14.分析下例说出错误的原因:class X{};X f(){return X();}void g1(X&){}void g2(const X&){}void main(){//! g1(f()); 临时变量都是常量g2(f());}15.如何使用类常量成员,如何初始化?class Y{public:const size;Y();};Y::Y():size(100){}class X{enum{i=100};};//! class X{//! const int i;//! X(){};//! };16.将一个成员函数声明为常量函数有什么作用?a. 编译器保证该函数不得修改成员变量的值b. 允许一个常量对象调用此函数class X{public:void f() const{cout<<"haha..."<<endl;}};void main(){const X cs;cs.f();}17.volatile关键字有什么作用?volatile告诉编译器不要对其做任何自作多情的假设与优化。
前言C++ Primer的第二版和第三版之间的变化非常大。
最引人注意的是,C++已经被国际标准化,这不但为语言增加了新的特性,比如异常处理、运行时刻类型识别(RTTI)、名字空间、内置布尔数据类型、新的强制转换方式,而且还大量修改并扩展了现有的特性,比如模板、支持面向对象(object-oriented)和基于对象(object-based)程序设计所需要的类(class)机制、嵌套类型、以及重载函数的解析机制。
也许更重要的是,一个覆盖面非常广阔的库现在成了标准C++的一部分,其中包括以前的标准模板库或STL。
新的string类型、一组顺序和关联容器类型——比如vector、list、map和set——以及在这些类型上进行操作的一组可扩展的泛型算法(generic algorithms),都是这个新标准库的特性。
本书不但包括了许多新的资料,而且还涵盖了怎样在C++中进行程序设计的新的思考方法。
简而言之,实际上,不但C++已经被重新创造,它的C++ Primer,第三版,也有了很大的变化。
在此第三版中,不但对语言的处理方式发生了根本的变化,而且作者本身也发生了变化:首先,我们的人数已经加倍。
而且,我们的写作过程也已经被国际化了(尽管我们还牢牢扎根于北美大陆):Stan是美国人,Josée是加拿大人。
最后,这个双作者关系也反映了C++团体的两类主要活动:Stan现在正在华特迪思尼动画公司(Walt Disney Feature Animation)致力于以C++为基础的3D计算机图形和动画应用,而Josée正专心于C++的定义与实现,同时她也是C++标准的核心语言小组的主席,以及IBM加拿大实验室的C++编译器组的成员。
Stan是Bell实验室中与Bjarne Stroustrup(C++的发明人)一起工作的早期成员之一,从1984年开始一直从事C++方面的工作。
Stan曾经致力于cfront的各种实现,从1986年的版本1.1到版本3.0,并领导了2.1和3.0版本的开发组。
RTTI、虚函数和虚基类的实现方式、开销分析及使用指导由上图得到每种特性的运行时开销如下:可见,关于老天“饿时掉馅饼、睡时掉老婆”等美好传说纯属谣言。
但凡人工制品必不完美,总有设计上的取舍,有其适应的场合也有其不适用的地方。
C++中的每个特性,都是从程序员平时的生产生活中逐渐精化而来的。
在不正确的场合使用它们必然会引起逻辑、行为和性能上的问题。
对于上述特性,应该只在必要、合理的前提下才使用。
"dynamic_cast" 用于在类层次结构中漫游,对指针或引用进行自由的向上、向下或交叉强制。
"typeid" 则用于获取一个对象或引用的确切类型,与 "dynamic_cast" 不同,将 "typeid" 作用于指针通常是一个错误,要得到一个指针指向之对象的type_info,应当先将其解引用(例如:"typeid(*p);")。
一般地讲,能用虚函数解决的问题就不要用"dynamic_cast",能够用 "dynamic_cast" 解决的就不要用 "typeid"。
比如:voidrotate(IN const CShape& iS){if (typeid(iS) == typeid(CCircle)){// ...}else if (typeid(iS) == typeid(CTriangle)){// ...}else if (typeid(iS) == typeid(CSqucre)){// ...}// ...}以上代码用 "dynamic_cast" 写会稍好一点,当然最好的方式还是在CShape里定义名为 "rotate" 的虚函数。
虚函数是C++众多运行时多态特性中开销最小,也最常用的机制。
常见⾯试题及答案(130题)1. 简述 private、 protected、 public、 internal 修饰符的访问权限。
答 . private : 私有成员, 在类的内部才可以访问。
protected : 保护成员,该类内部和继承类中可以访问。
public : 公共成员,完全公开,没有访问限制。
internal: 在同⼀命名空间内可以访问。
2 .列举 页⾯之间传递值的⼏种⽅式。
答. 1.使⽤QueryString, 如....?id=1; response. Redirect()....2 .使⽤Session变量3.使⽤Server.Transfer4.C#中的委托是什么?事件是不是⼀种委托?答:委托可以把⼀个⽅法作为参数代⼊另⼀个⽅法。
委托可以理解为指向⼀个函数的引⽤。
是,是⼀种特殊的委托5.override与重载的区别答:重载是⽅法的名称相同。
参数或参数类型不同,进⾏多次重载以适应不同的需要Override 是进⾏基类中函数的重写。
为了适应需要。
6.如果在⼀个B/S结构的系统中需要传递变量值,但是⼜不能使⽤Session、Cookie、Application,您有⼏种⽅法进⾏处理?答: this.Server.TransferResponse. Redirect()---QueryString9.描述⼀下C#中索引器的实现过程,是否只能根据数字进⾏索引?答:不是。
可以⽤任意类型。
11.⽤.net做B/S结构的系统,您是⽤⼏层结构来开发,每⼀层之间的关系以及为什么要这样分层?答:⼀般为3层:数据访问层,业务层,表⽰层。
数据访问层对数据库进⾏增删查改。
业务层⼀般分为⼆层,业务表观层实现与表⽰层的沟通,业务规则层实现⽤户密码的安全等。
表⽰层为了与⽤户交互例如⽤户添加表单。
优点:分⼯明确,条理清晰,易于调试,⽽且具有可扩展性。
缺点:增加成本。
13.什么叫应⽤程序域?答:应⽤程序域可以理解为⼀种轻量级进程。
codewarrior的pathentry编译问题第一步:理解编译阶段我们的前面的课程中已经学到,源程序输入完之后的工作就是要编译它。
编译源程序就是计算机把你所写(通常是用C 或 C++编写的)的源代码进行分解、分析,然后转化为机器语言。
机器语言是一种计算机能够理解阿语言,而且它运行起来比 C 或 C++ 也要快得多。
编译的大致过程如下:1. 用C或C++ 编写代码:2. 进行编译。
CodeWarrior 编译上述代码并把它翻译成机器语言,结果如下:上述机器代码难于阅读,不要去管它。
机器代码相比 C 或 C++ 而言,要难理解多了。
但是,计算机只能理解机器语言。
只有将你的程序编译—或翻译—成机器代码,然后再执行它,这样运行起来才能快一些,而不是每次运行时才去翻译它,那样运行速度就很慢了。
你只需选定一个源文件,然后从工程菜单中选择反汇编项,你就能看到该文件的机器语言清单。
实际上上面我们看到的机器语言清单就是这样得到的。
如果你仔细地对照阅读一下你的 C 或 C++ 源代码和它编译后的机器代码,不难发现它们之间的关系。
CodeWarrior 中编译选项的详细设置在正式开始编译源代码之前,CodeWarrior 还要对其做预处理。
在这个阶段,是对 C 或 C++ 代码进行编译前的一些准备工作。
在编写程序的过程中,往往会有很多相同的P代码输入,于是程序员使用一些快捷方式,比如所谓的宏(macros)来代替这些相同的输入。
例如,你可以使用 APPNAME 作为一个宏,来表示“Metrowerks CodeWarrior”,以此来减少输入的工作量。
预处理就是要把这些宏转换为它们实际表示的代码,此外还要替换一些定义符号(比如#define THREE 3)为实际的源代码。
为了更好地理解预处理所做的工作,你可以查看一下预处理结果的清单。
首先在工程窗口中选中一个源文件,然后从工程菜单中选择预处理项,你就可以看到源代码进行了预处理之后,编译之前的结果清单了。
名称空间namespaceC++名字空间主要就是用来避免类名的冲突,尤其是在大项目中,它的作用体现非常明显。
#include <cstdlib>#include <iostream>using namespace std;float float1 = 88.8f; //全局变量::namespace//未命名名字空间{float unnamespacefloat = 99.9f;}namespace ns1//名字空间ns1{const int integer1 = 100;const double double1 = 100.5;float float1 = 99.9f;void printValue();namespace Inner//内嵌名字空间{double innerdouble = 55.5;}}void main(void){cout<<"全局变量”<< ::float1 <<endl;cout << "未命名名字空间变量" << unnamespacefloat << endl;cout << "ns1::integer1 = " <<ns1::integer1 << endl;cout << "ns1::double1 = " << ns1::double1 << endl;cout << "ns1::float1 = " << ns1::float1 << endl;cout << "ns1::Inner::innerdouble = " << ns1::Inner::innerdouble <<endl;ns1::printValue();}void ns1::printValue()//ns1中输出函数的实现{cout <<::float1 << endl;cout <<unnamespacefloat << endl;cout << "integer1 = " << integer1 << endl;cout << "double1 = " << double1 << endl;cout << "float1 = " << float1 << endl;cout << "Inner::innerdouble = " << Inner::innerdouble << endl;}RTTI介绍runtime typeinfo多态RTTI提供了以下两个非常有用的操作符:(1)typeid操作符,返回指针和引用所指的实际类型;(2)dynamic_cast操作符,将基类类型的指针或引用安全地转换为派生类型的指针或引用。
异常处理-命名空间-RTTI异常处理-命名空间-RTTI (1)1. 异常处理一般性概念 (1)2. C++标准异常处理 (6)2.1. C++异常处理 (6)2.2. 多个异常的组织 (13)2.3. 异常接口说明 (20)3. MFC异常处理 (21)4. Win32结构化异常处理(SEH) (26)4.1. __try{}__finally{}结构 (27)4.2. __try{}__except(){}结构 (29)4.3. SEH到标准C++异常处理的转换 (34)5. 命名空间 (36)5.1. C语言的命名控制 (36)5.2. 命名空间的目标和定义 (37)5.3. 未命名的命名空间--命名空间后没有定义名字 (39)5.4. 命名空间的使用 (39)6. RTTI运行时类型信息 (41)6.1. RTTI的两种使用方法 (41)1.异常处理一般性概念修复技术是提高代码健壮性的最有效方法之一。
C语言中实现错误处理的方法是将函数调用与错误处理程序紧密结合起来,这使得错误处理的使用很不方便。
在传统的C 语言程序设计中,一个函数的出错信息往往是通过函数的返回值获得,这就要求函数的使用者在每次的函数调用时都要进行相应的错误判断,有时,返回值所包含的错误信息较为复杂时,对出错信息的判断和处理也变的非常复杂,而且对同一函数的重复调用往往要伴随着对错误信息的重复判断和处理。
这样的异常处理方式使得程序代码既累赘,可读性又差。
而且往往因为缺乏条理而遗漏对某个错误的处理。
异常处理通过把异常的检查和异常的处理分开,使得程序的代码简洁、清晰、可读性强。
例:假设有一个初始化数据库的函数InitDb(),它需要调用创建数据库的函数CreateDb(),创建用户及授权函数CreateUser(),创建表函数CreateTable(),CreateTable()又调用创建索引的函数CreateIndex():每个函数都以返回值表示处理的结果,在InitDb()的返回值中,如果既要包含最终的错误信息,又要包含那一层次调用出错的信息,一种代码的形式为:int CreateUser(){//...}int CreateIndex(){//...}int CreateTable(){//....if((iRet=CreateIndex())<0)//错误处理}int CreateDb(){//...}int InitDb(){if((iRet=CreateDb())==0){if((iRet=CreateUser())==0){if((iRet=CreateTable()==0)){//...return 0;}else{//错误处理return ??;}}else{//错误处理return ??}}else{//错误处理return ??}}//或者int InitDb(){if((iRet=CreateDb())<0){//错误处理//return ??}if((iRet=CreateUser())<0){//错误处理//return ??}if((iRet=CreateTable()<0)){//错误处理//return ??}return 0;}代码变得复杂而难以维护,而如果使用异常处理,可简化为如下形式void CallFunc(){try{InitDb();}catch(???){//异常处理}}void InitDb(){CreateDb(); //在CreateDb()内部如果执行失败,抛出异常CreateUser(); //在CreateUser()内部如果执行失败,抛出异常CreateTable(); //在CreateTable()函数内部如果执行失败,抛出异常}例子:写一个程序计算公式值n!+|a|+∑n(n等负数时出错处理,a=0时出错处理,a,n可以从键盘输入也可以给定)2.C++标准异常处理2.1.C++异常处理C++的异常处理分为两部分,第一部分是检查程序处理情况,如果处理结果非期望的结果,则生成一个异常,并将异常抛出,抛出后,由异常的接收者处理这个异常,异常抛出的语法形式为:throw 异常对象throw是C++关键字,表示要抛出异常。
c++简介C++是一种使用非常广泛的电脑程序设计语言。
它是一种静态数据类型检查的,支持多范型的通用程序设计语言。
C++支持过程化程序设计、数据抽象化、面向对象程序设计、泛型程序设计、基于原则设计等多种程序设计风格。
贝尔实验室的比雅尼·斯特劳斯特鲁普博士在20世纪80年代发明并实现了C++。
起初,这种语言被称作“C with Classes”(“包含类的C语言”),作为C 语言的增强版出现。
随后,C++不断增加新特性。
虚函数(virtual function)、操作符重载(operator overloading)、多重继承(multiple inheritance)、模板(template)、异常处理(exception)、RTTI(Runtime type information)、命名空间(namespace)逐渐纳入标准。
1998年国际标准组织(ISO)颁布了C++程序设计语言的国际标准ISO/IEC 14882-1998。
另外,就目前学习C++而言,可以认为它是一门独立的语言;它并不依赖C语言,我们可以完全不学C 语言,而直接学习C++。
根据《C++编程思想》(Thinking in C++)一书所评述的,C++与C的效率往往相差在正负5%之间。
所以有人认为在大多数场合中,C++完全可以取代C语言。
C++语言发展大概可以分为三个阶段:第一阶段从80年代到1995年。
这一阶段C++语言基本上是传统类型上的面向对象语言,并且凭借着接近C语言的效率,在工业界使用的开发语言中占据了相当大份额;第二阶段从1995年到2000年,这一阶段由于标准模板库(STL)和后来的Boost等程序库的出现,泛型程序设计在C++中占据了越来越多的比重性。
当然,同时由于Java、C#等语言的出现和硬件价格的大规模下降,C++受到了一定的冲击;第三阶段从200 0年至今,由于以Loki、MPL等程序库为代表的产生式编程和模板元编程的出现,C++出现了发展历史上又一个新的高峰,这些新技术的出现以及和原有技术的融合,使C++已经成为当今主流程序设计语言中最复杂的一员。
问题:Delphi 的RTTI机制浅探( 积分:100, 回复:21, 阅读:352 )分类:Object Pascal ( 版主:menxin, cAkk )来自:savetime, 时间:2004-1-21 0:48:00, ID:2420610 [显示:小字体| 大字体] Delphi 的RTTI机制浅探savetime2k@ 2004.1.20目录===============================================================================⊙RTTI 简介⊙类(class) 和VMT 的关系⊙类(class)、类的类(class of class)、类变量(class variable) 的关系⊙TObject.ClassType 和TObject.ClassInfo⊙is 和as 运算符的原理⊙TTypeInfo –RTTI 信息的结构⊙获取类(class)的属性(property)信息⊙获取方法(method)的类型信息⊙获取有序类型(ordinal)、集合(set)类型的RTTI 信息⊙获取其它数据类型的RTTI 信息===============================================================================本文排版格式为:正文由窗口自动换行;所有代码以80 字符为边界;中英文字符以空格符分隔。
(作者保留对本文的所有权利,未经作者同意请勿在在任何公共媒体转载。
)正文=============================================================================== ⊙RTTI 简介===============================================================================RTTI(Run-Time Type Information) 翻译过来的名称是“运行期类型信息”,也就是说可以在运行期获得数据类型或类(class)的信息。