内联函数在运行时可调试,而宏定义不可以。 虚函数(virtual)可以是内联函数(inline)吗?...Base b; b.who(); // 此处的虚函数是通过指针调用的,呈现多态性,需要在运行时期间才能确定,所以不能为内联。...虚函数指针、虚函数表 虚函数指针:在含有虚函数类的对象中,指向虚函数表,在运行时确定。...(析构调用 delete),unique_ptr 可以管理数组(析构调用 delete[] ); 强制类型转换运算符 static_cast 用于非多态类型的转换 不执行运行时类型检查(转换安全性不如...(RTTI) dynamic_cast 用于多态类型的转换 typeid typeid 运算符允许在运行时确定对象的类型 type_id 返回一个 type_info 对象的引用 如果想通过基类的指针获得派生类的数据类型
用sizeof来返回类型以及静态分配的对象、结构或数组所占的空间,返回值跟对象、结构、数组所存储的内容没有关系;strlen是字符处理的库函数,当数组名作为参数传入时,实际上数组就退化成指针了。。...3.对于Union的不同成员赋值,将会对其他成员重写,原来成员的值就不存在了,而对于struct 的不同成员赋值 是互不影响的。...当delete一个对象数组时,delete只删除了一个,需要使用delete[] const 宏定义和const函数的区别 宏在编译时完成替换,直接进行替换,执行起来更快,但是可能会存在一些风险;函数调用在运行时需要跳转到具体调用函数...原理也很清晰,构造函数,由于构造顺序是从基类到派生类,所以调用虚函数,可能派生类还没有构造出来,没有意义。...浅拷贝和深拷贝: 多态 多态:对于不同对象接收相同消息时产生不同的动作。C++的多态性具体体现在运行和编译两个方面: 编译时多态:函数和运算符的重载。 运行时多态:继承和虚函数。
内部数据类型没有析构函数,所以问题不大。如果你在用delete时没用括号,delete就会认为指向的是单个对象,否则,它就会认为指向的是一个数组。 3.C和C++ 的共同点?不同之处?...首先,因为继承在编译时刻就定义了,所以无法在运行时刻改变从父类继承的实现。更糟的是,父类通常至少定义了子类的部分行为,父类的任何改变都可能影响子类的行为。...C++的多态性具体体现在运行和编译两个方面:在程序运行时的多态性通过继承和虚函数来体现; 在程序编译时多态性体现在函数和运算符的重载上 虚函数:在基类中冠以关键字 virtual 的成员函数。...从基类继承来的纯虚函数,在派生类中仍是虚函数。如果一个类中至少有一个纯虚函数,那么这个类被称为抽象类(abstract class)。 抽象类中不仅包括纯虚函数,也可包括虚函数。...l抽象类必须用作派生其他类的基类,而不能用于直接创建对象实例。但仍可使用指向抽象类的指针支持运行时多态性。
NSObject还有些方法能在运行时获得类的信息,并检查一些特性,比如class返回对象的类;isKindOfClass:和isMemberOfClass:则检查对象是否在指定的类继承体系中;respondsToSelector...SEL数据类型:查找方法表时所用的键。定义成char*,实质上可以理解成int值。 IMP数据类型:他其实就是一个编译器内部实现时候的函数指针。...2、KVO 当某个类的对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的 setter 方法。...然后系统将这个对象的 isa 指针指向这个新诞生的派生类,因此这个对象就成为该派生类的对象了,因而在该对象上对 setter 的调用就会调用重写的 setter,从而激活键值通知机制。...利用Objective-C的动态特性,可以实现在运行时偷换selector对应的方法实现,达到给方法(Hook)挂钩的目的。
程序之所以能够在运行时选择正确的虚函数,必定隐藏了一段运行时进行对象类型判断或是函数寻址的代码。...,最后改写为指针运算 派生类定义中的名字(对象或函数名)将义无反顾地遮蔽(隐藏)基类中任何同名的对象或函数 函数原型完全相同,当返回类型不同时称为协变 运行时多态 当许多的派生类因为继承了共同的基类而建立...is -a 关系时,没一个派生类的对象都可以被当成基类的对象来使用,这些派生类对象能对同一个函数调用做出不同的反应,这就是运行时多态。 ...可以大大提高程序的可复用性和可扩展性。派生类的功能可以被基类指针引用,这叫向后兼容。以前写的程序可以被将来写的程序调用,这不足为奇,但是将来写的程序可以被以前写的程序调用那就很了不起了。 ...该类的继承链中至少有一个基类是多态类该类至少有一个虚基类该类包含了多态的成员对象,但是该类不一定是多态类 显然,当创建一个对象的时候,其隐含的成员vfptr必须被初始化为指向正确的vtable,而且这个初始化工作只能在运行时完成
strlen和sizeof的区别如下所述: strlen()是函数,在运行时才能计算,参数必须是字符型指针(char *),且必须是以\0结尾的。...因此,sizeof 不能用来返回动态分配的内存空间的大小 sizeof 常用于返回类型和静态分配的对象、结构或数组所占的空间,返回值跟对象、结构、数组所存储的内容没有关系。...当参数分别如下时 sizeof 返回的值表示的含义如下所述: 数组一一编译时分配的数组空间大小 指针一一存储该指针所用的空间大小(int类型大小,32位机器为4 Byte) 类型一一该类型所占的空间大小...共用体的声明方式为: union 共用体类型名{ 数据类型 成员名; 数据类型 成员名; ... }变量名; 可以使用 union 判断系统是 big endian (大端)还...union的字节数计算 union 变量共用内存应以最长的为准,同时共用体内变量的默认内存对齐方式以最长的类型对齐。
; } ---- 19.2 运行时类型识别 **运行时类型识别(RTTI)**的功能由两个运算符实现: typeid运算符,用于返回表达式的类型 dynamic_cast运算符,用于将基类的指针或引用安全地转换为派生类的指针或引用...当运算对象是定义了至少一个虚函数的类的左值时,编译器才会对表达式求值,即确定其运行时类型。...Derived *dp = new Derived; Base *bp = dp; // 两个指针都指向 Derived对象 // 在运行时比较两个对象的类型 if (typeid(*bp)...根据成员指针的类型推断可调用对象的类型,而无需用户显示的指定。生成的可定对象可以通过对象调用,也可以通过指针调用。...但是对于含有特殊类类型成员的 union就没这么简单了。如果我们想将 union的值改为类类型成员对应的值,或者将类类型成员的值改为一个其他值,则必须分别构造或析构该类型的成员。
定位new和allocator的construct最大区别是定位new可以接受任意的指针内存,甚至不需要是动态内存 这两个operator一样可以被当作普通函数调用 19.2 运行时类型识别 运行时类型识别...typeid可以返回表达式的类型,dynamic_cast将基类的指针或引用强制转为派生类的指针或引用 dynamic_cast有模板参数,是目标要转换的类型,通常情况下应该有虚函数,是指针,左值引用或右值引用...typeid不会自动进行指针的标准类型转换,也就是当e是数组时返回的是数组类型而不是指针类型 当目标e没有虚函数时,typeid返回的是目标的静态类型,当e是定义了至少一个虚函数的类的左值时,结果会到运行时才求得...中我们可以先声明一个枚举类,然后后面再定义它,但是类似数组的声明,我们需要保证声明时整个枚举类的空间是可确定的,也就是我们必须指定限定作用域的枚举类的成员类型 19.4 类成员指针 成员指针给了我们一种指向类的非静态成员的方法...union,默认情况下这个值会被用来初始化union的第一个值 对union的一个值进行赋值会让其他的成员变为未定义的状态,因此我们需要时刻记得union此时有效的值是什么,一般来说我们通过在外层再包装一个类
在进行函数重写时,子类中的虚函数的返回值类型、函数名、参数列表必须与基类中的虚函数完全相同 注意:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承后在派生类依旧保持虚函数属性...2.2.3虚函数重写的两个例外 协变(基类与派生类虚函数返回值类型不同) 派生类重写基类虚函数时,与基类虚函数返回值类型不同。...这种动态绑定的过程使得程序在运行时能够根据对象的实际类型来调用正确的虚函数,实现了多态性 为什么多态必须要用基类的指针 / 引用来调用虚函数,而用基类对象调用却不行 当派生类对象赋值给基类对象时...多态必须使用基类的指针/引用来调用虚函数的原因主要是因为基类指针/引用可以在运行时指向派生类对象,而且能正确地调用派生类的虚函数。...这是因为在运行时,基类指针/引用会指向实际对象的虚表,从而实现了动态绑定,根据对象的实际类型调用正确的虚函数 4.3动态绑定与静态绑定 静态绑定又称为前期绑定(早绑定),在程序编译期间确定了程序的行为
而析构函数一般写成虚函数的原因 ? 1、构造函数不能声明为虚函数 1)因为创建一个对象时需要确定对象的类型,而虚函数是在运行时确定其类型的。...十四、静态绑定和动态绑定的介绍: 静态绑定和动态绑定是C++多态性的一种特性 1)对象的静态类型和动态类型 静态类型:对象在声明时采用的类型,在编译时确定 动态类型:当前对象所指的类型,在运行期决定,...对象的动态类型可变,静态类型无法更改 2)静态绑定和动态绑定 静态绑定:绑定的是对象的静态类型,函数依赖于对象的静态类型,在编译期确定 动态绑定:绑定的是对象的动态类型,函数依赖于对象的动态类型,在运行期确定...因为引用(或指针)既可以指向基类对象也可以指向派生类对象,这一事实是动态绑定的关键。用引用(或指针)调用的虚函数在运行时确定,被调用的函数是引用(或指针)所指的对象的实际类型所定义的。...用于在集成体系中进行安全的向下转换downcast,即基类指针/引用->派生类指针/引用 dynamic_cast是4个转换中唯一的RTTI操作符,提供运行时类型检查。
运行时类型识别 运行时类型识别run-time type identification, RRTTI的功能由两个运算符实现: typeid运算符,用于返回表达式的类型 dynamic_cast运算符,用于将基类的指针或引用安全地转换成派生类的指针或引用...而当运算对象是定义了至少一个虚函数的类的左值时,typeid的结果直到运行时才会求得。...Derived对象 // 在运行时比较两个对象的类型 if (typeid(*bp) == type(*dp)) { // bp和dp指向通医药类型对象 } // 检查类型是否是某种指定类型...= t2:如果type_info对象t1和t2表示不同的类型,则返回true t.name():返回一个C风格字符串,表示类型名字的可打印形式 t1.before(t2):返回一个bool值,表示t1...举个例子,假设我们需要处理一些不同种类的数字数据和字符数据,则可以定义一个union来保存这些值: // Token类型的对象只有一个成员, 该成员的类型可能是下列类型中的任意一个 union Token
Union 整体空间是 占用空间最大的成员(的类型)所占字节数的整倍数。...union的成员共享内存空间,修改某成员值会影响其他成员。...指针数组相当于一个变量,存放的是其它变量在内存中的地址储存多个相同类型数据的集合同类型指针可相互赋值数组只能一个个拷贝元素存储很灵活,可指向任意类型的数据存在一块连续的物理空间上,逻辑上的多维数组其实存的是一维...调用函数的形参对象必须是基类对象,因为派生类能给基类赋值,基类不能给派生类赋值。...若派生类中有一个跟基类的完全相同虚函数(函数名、参数、返回值相同),我们就称子类的虚函数重写了基类的虚函数。 协变:重写虚函数的返回值可以不同,但是必须分别是基类指针或引用和派生类指针或引用。
后期绑定也称为动态绑定或运行时绑定。当一种语言实现了后期绑定,就必须具有某种机制在运行时能判断对象的类型,从而调用恰当的方法。...这样的程序是可扩展的,因为可以从通用的基类派生出新的数据类型,从而添加新的功能。那些操纵基类接口的方法不需要改动就可以应用于新类。...如果在构造器中调用了正在构造的对象的动态绑定方法,会发生什么呢? 在普通的方法中,动态绑定的调用是在运行时解析的,因为对象不知道它属于方法所在的类还是类的派生类。...这么做有个优点:所有事物至少初始化为 0(或某些特殊数据类型与 0 等价的值),而不是仅仅留作垃圾。这包括了通过组合嵌入类中的对象引用,被赋予 null。如果忘记初始化该引用,就会在运行时出现异常。...这种在运行时检查类型的行为称作运行时类型信息。
虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的 返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。...要注意的是虚函数的重写有两个意外: 1. 协变(基类与派生类虚函数返回值类型不同) 派生类重写基类虚函数时,与基类虚函数返回值类型不同。...对虚函数的调用可能在运行时才被解析 当某个虚函数通过指针或引用调用时,编译器产生的代码直到运行时才能确定应该调用哪个版本的函数。被调用的函数是与绑定到指针或引用上的对象的动态类型相匹配的那一个。...注意:如果一个派生类虚函数需要调用它的基类版本,但是没有使用作用域运算符,则在运行时该调用将被解析为对派生类版本自身的调用,从而导致无限递归。...虚函数表本质是一个存虚函数指针的指针数组,一般情况这个数组最后面放了一nullptr。 5.
从堆上分配(动态内存分配)程序在运行的时候用malloc或new申请任意多少的内存,程序员负责在何时用free或delete释放内存。动态内存的生存期自己决定,使用非常灵活。...宏在编译时完成替换,之后被替换的文本参与编译,相当于直接插入了代码,运行时不存在函数调用,执行起来更快;函数调用在运行时需要跳转到具体调用函数。...&a是数组的指针,其类型为int (*)[10](就是前面提到的数组指针),其加1时,系统会认为是数组首地址加上整个数组的偏移(10个int型变量),值为数组a尾元素后一个元素的地址。...宏定义没有类型检查,但是内联函数还是具有函数的性质,有参数以及返回值。 26、struct与union的区别? struct可以存储多个成员变量信息;而union每个成员会共用同一个存储空间。...每次使用它的时候必须从内存中取出它的值,因而编译器生成的汇编代码会重新从它的地址处读取数据放在左值中。
const char *pc; char *p = const_cast(pc); dynamic_cast 相比static_cast,dynamic_cast会在运行时检查类型转换是否合法...指针p也是对象,它同样有地址&p和存储的值p,只不过,p存储的数据类型是数据的地址。如果我们要以p中存储的数据为地址,来访问对象的值,则要在p前加解引用操作符”“,即p。...存取效率的比较 char s1[] = "aaaaaaaaaaaaaaa"; char *s2 = "bbbbbbbbbbbbbbbbb"; aaaaaaaaaaa是在运行时刻赋值的...它虚就虚在所谓“推迟联编”或者“动态联编”上,一个类函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的。...8、析构函数应当是虚函数,将调用相应对象类型的析构函数,因此,如果指针指向的是子类对象,将调用子类的析构函数,然后自动调用基类的析构函数。有纯虚函数的类是抽象类,不能生成对象,只能派生。
对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。...定义一个对象时先调用基类的构造函数、然后调用派生类的构造函数;析构的时候恰好相反:先调用派生类的析构函数、然后调用基类的析构函数 5.C++中的class和struct的区别 从语法上,在C++中(只讨论...这意味着,一个基类的引用可以指向它的派生类实例 a) #include union{ int i; char x[2]; }a; void main(){ a.x[0] = 10;/...程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多。 BOOL : if ( !...2)有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。 10.简述数组与指针的区别? 数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。
整型数组 数组的大小是指定元素的数目,必须是整型常数或const值,也可以是常量表达式(8*sizeof(int)) 1.3 复合类型的数组 可以使用其他的类型来创建(C语言使用术语:派生类型) 数组的用途...关键字:union 联合(union):将不同类型的数据在一起共同占用同一段内存 存储不同的数据类型,但只能同时存储其中的一种类型 示例: union sample { int int_val;...C++语言数字不能作为地址使用,如果要把数字当地址来使用,应通过强制类型转换将数字转换为适当的地址类型。 7.4 使用new分配和delete释放内存 指针在运行阶段 分配未命名的内存以存储值。...int tacos[10] // 静态联编 使用new[]运算符创建数组时,将采用动态联编(动态数组),即将在运行时为数组分配空间,其长度为运行时设置。...从地址可知,array对象和数组存储在相同的内存区域(即栈)中,vector对象存储在自由存储区域或堆中。 可以将一个array对象赋给另一个array对象,对于数组,必须逐个元素复制数据。
领取专属 10元无门槛券
手把手带您无忧上云