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

竞价网站和优化网站的区别你注册过的那些网站

竞价网站和优化网站的区别,你注册过的那些网站,网站建设服务 行业代码,phpcms转wordpress继承和多态 一、继承1. 继承概念2. 继承定义#xff08;1#xff09;继承的格式定义#xff08;2#xff09;继承父类成员访问方式的变化 3. 父类和子类对象赋值转换4. 继承中的作用域5. 子类的默认成员函数6. 继承与友元7. 继承与静态成员8. 复杂的菱形继承及菱形虚拟继承… 继承和多态 一、继承1. 继承概念2. 继承定义1继承的格式定义2继承父类成员访问方式的变化 3. 父类和子类对象赋值转换4. 继承中的作用域5. 子类的默认成员函数6. 继承与友元7. 继承与静态成员8. 复杂的菱形继承及菱形虚拟继承1继承类型2虚拟继承解决数据冗余和二义性的原理 9. 继承的总结 二、多态1. 多态的概念2. 多态的定义及实现1多态的构成条件2虚函数3虚函数的重写3override 和 final4重载、覆盖(重写)、隐藏(重定义) 3. 抽象类1概念2接口继承和实现继承 4. 多态的原理1虚函数表2多态的原理3动态绑定与静态绑定 5. 虚函数和虚表存在于哪里6. 单继承中的虚函数表 一、继承 1. 继承概念 继承机制是面向对象程序设计使代码可以复用的最重要的手段它允许程序员在保持原有类特性的基础上进行扩展增加功能这样产生新的类称派生类/子类。继承呈现了面向对象程序设计的层次结构体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用继承是类设计层次的复用。 我们先简单看一下继承的使用如以下代码 class Person{public:void Print(){cout name: _name endl;cout age: _age endl;}protected:string _name Mike;int _age 18;};// 继承 Person 父类class Student : public Person{protected:string s_id;};// 继承 Person 父类class Tercher : public Person{protected:string t_id;};继承后父类的 Person 的成员成员函数成员变量都会变成子类的一部分。这里体现出了 Student 和 Teacher 复用了 Person 的成员。下面我们使用监视窗口查看 Student 和 Teacher 对象可以看到变量的复用调用 Print 可以看到成员函数的复用如下代码 int main(){Person p;Student s;Tercher t;p.Print();s.Print();t.Print();return 0;}我们先观察监视窗口 我们可以看到s 和 t 都继承了父类的成员变量再尝试调用父类的成员函数 2. 继承定义 1继承的格式定义 继承的定义格式如下Person 是父类/基类Student 是子类/派生类public 为继承方式 2继承父类成员访问方式的变化 继承父类成员访问方式的变化如下表 其中以 public 继承方式我们称父类和子类是一种 is-a 关系也就是“我是一个你”。 总结 父类 private 成员在子类中无论以什么方式继承都是不可见的。这里的不可见是指父类的私有成员还是被继承到了派生类对象中但是语法上限制子类对象不管在类里面还是类外面都不能去访问它。父类 private 成员在子类中是不能被访问如果父类成员不想在类外直接被访问但需要在子类中能访问就定义为 protected。可以看出保护成员限定符是因继承才出现的。父类的私有成员在子类都是不可见。父类的其他成员在子类的访问方式 min(成员在基类的访问限定符继承方式)其中比较规则public protected private.使用关键字 class 时默认的继承方式是 private使用 struct 时默认的继承方式是 public不过最好显示的写出继承方式。在实际运用中一般使用都是 public 继承几乎很少使用 protetced/private 继承也不提倡使用 protetced/private 继承因为 protetced/private 继承下来的成员都只能在派生类的类里面使用实际中扩展维护性不强。 下面演示 public 继承关系下父类成员的各类型成员访问关系的变化 // Print() 函数在父类中是 pubilc 成员class Person{public:void Print(){cout _name endl;}protected:string _name Mike; // 姓名};// public 继承父类class Student : public Person{public:Student():_stuid(000){Print();}protected:int _stuid; // 学号};int main(){Student s;s.Print();return 0;}如上Print() 函数在父类中是 pubilc 成员子类继承方式也是 public所以此时 Print() 在类内类外都可访问如下 当我们将 Print() 的访问限定符改为 protected 后如下 // Print() 函数在父类中是 protected 成员class Person{protected:void Print(){cout _name endl;}protected:string _name Mike; // 姓名};那么此时 Print() 函数只能在子类中使用在类外不可使用 3. 父类和子类对象赋值转换 子类对象可以赋值给父类的对象 / 父类的指针 / 父类的引用。这里有个形象的说法叫切片或者切割。寓意把子类中父类那部分切来赋值过去如下图所示 父类对象不能赋值给子类对象因为子类就是继承父类下来的父类有的子类也有。 如下示例 class Person{protected:string _name;int _age;};class Student : public Person{public:string s_id;};int main(){Student s;// 1.子类对象可以赋值给父类对象/指针/引用Person p s;Person* pp s;Person rp s;// 2.基类的指针可以通过强制类型转换赋值给派生类的指针pp s;Student* ps1 (Student*)pp; // 这种情况转换时可以ps1-s_id 7;pp p;Student* ps2 (Student*)pp; // 这种情况转换时虽然可以但是会存在越界访问ps2-s_id 3;return 0;}4. 继承中的作用域 在继承体系中父类和子类都有独立的作用域。父类和子类中有同名成员子类成员将屏蔽父类对同名成员的直接访问这种情况叫隐藏也叫重定义。在子类成员函数中可以使用 父类::基类成员 显示访问需要注意的是如果是成员函数的隐藏只需要函数名相同就构成隐藏。注意在实际中在继承体系里面最好不要定义同名的成员。 例如以下示例 class A{public:void fun(){cout func() endl;}};class B : public A{public:void fun(int i){A::fun(); // 可显示调用 A 类的 fun 函数cout func(int i)- i endl;}};int main(){B b;b.fun(10); // 默认调的是 B 类的 fun 函数b.A::fun(); // 可显示调用 A 类的 fun 函数return 0;}B 中的 fun 和 A 中的 fun 不是构成重载因为不是在同一作用域而是构成隐藏成员函数满足函数名相同就构成隐藏。 5. 子类的默认成员函数 6个默认成员函数“默认”的意思就是指我们不写编译器会变我们自动生成一个那么在子类中这几个成员函数是如何生成的呢 子类的构造函数必须调用父类的构造函数初始化父类的那一部分成员。如果父类没有默认的构造函数则必须在子类构造函数的初始化列表阶段显示调用。 子类的拷贝构造函数必须调用父类的拷贝构造完成父类的拷贝初始化。 子类的 operator 必须要调用父类的 operator 完成基类的复制。 子类的析构函数会在被调用完成后自动调用父类的析构函数清理父类成员。因为这样才能保证子类对象先清理子类成员再清理父类成员的顺序。 子类对象初始化先调用父类构造再调子类构造。 子类对象析构清理先调用子类析构再调父类的析构。 因为后续一些场景析构函数需要构成重写重写的条件之一是函数名相同(后面会讲解)。那么编译器会对析构函数名进行特殊处理处理成 destrutor()所以父类析构函数不加 virtual 的情况下子类析构函数和父类析构函数构成隐藏关系。 下面演示继承中构造函数和析构函数的调用情况 class A{public:A() { cout A() endl; }~A() { cout ~A() endl; }private:int _a;};class B : public A{public:B() { cout B() endl; }~B() { cout ~B() endl; }};上述代码中我们实例化B对象编译器会先调用父类的构造即先调A的构造然后再构造子类B析构顺序按照先子后父例如下图 6. 继承与友元 友元关系不能继承也就是说父类友元不能访问子类私有和保护成员。简单一句话说就是父类的友元并不是子类的友元所以不能继承下来。 7. 继承与静态成员 父类定义了 static 静态成员则整个继承体系里面只有一个这样的成员。无论派生出多少个子类都只有一个 static 成员实例。 8. 复杂的菱形继承及菱形虚拟继承 1继承类型 1. 单继承一个子类只有一个直接父类时称这个继承关系为单继承。 2. 多继承一个子类有两个或以上直接父类时称这个继承关系为多继承。 3. 菱形继承菱形继承是多继承的一种特殊情况。 菱形继承的问题从下面的对象成员模型构造可以看出菱形继承有数据冗余和二义性的问题。以上图为例在 D 的对象中 A 成员会有两份如下图 用代码来说明如下代码为四个类以以上的方式继承 class A{public:int _a;};class B : public A{public:int _b;};class C : public A{public:int _c;};class D : public B, public C{public:int _d;};我们尝试实例化一个D类对象d先尝试修改d对象中的 _b 值 如上图是没有问题的我们再尝试修改d对象中的 _a 值 如上图可以看出编译不通过理由就是对 _a 的访问不明确就是因为存在二义性在 d 中存有两份 _a编译器不知道我们访问的是哪一个 但是我们可以指定访问域如下图 因为在 B 中和 C 中各有一份 _a所以我们可以指定 B 中的 _a或者 C 中的 _a 进行指定操作这样就解决二义性问题了但是数据冗余还没有解决。 但是有一种方法可以既解决二义性也解决数据冗余问题就是虚拟继承。虚拟继承可以解决菱形继承的二义性和数据冗余的问题。 如上面的继承关系在 B 和 C 继承 A 时使用虚拟继承即可解决问题。需要注意的是虚拟继承不要在其他地方去使用。 我们用代码演示证明一下首先我们在 B 和 C 继承 A 时加上 virtual 关键字说明是虚拟继承 class A{public:int _a;};class B : virtual public A{public:int _b;};class C : virtual public A{public:int _c;};class D : public B, public C{public:int _d;};接下来我们直接实例化 D 对象并访问 _a如下图 如上二义性问题就解决了那么我们看看 d 对象中 B 和 C 中的 _a 的值 我们观察可知d 对象中继承下来的类里面的 _a 都是 1也就是说这个 _a 在这个 d 对象中只有一份那就说明虚拟继承也解决了数据冗余问题了 2虚拟继承解决数据冗余和二义性的原理 首先我们先通过调试观察一下普通菱形继承中d 对象中的内存分布如下图所示 我们可以观察到 d 对象中有两份 _a 明显的数据冗余。 接下来我们加上虚拟继承继续观察 d 对象中的内存分布如下图 上图是菱形虚拟继承的内存对象成员模型这里可以分析出 D 对象中将 A 放到的了对象组成的最下面这个 A 同时属于 B 和 C那么 B 和 C 如何去找到公共的 A 呢这就和 B 和 C 中多了两个地址有关系了这两个地址是什么呢我们可以取它们的地址到内存窗口去观察一下 这里是通过了 B 和 C 的两个指针指向的一张表。这两个指针叫虚基表指针这两个表叫虚基表。虚基表中存的是偏移量通过偏移量可以找到下面的 A。例如上图中 B 中的指针指向的虚基表中它的偏移量是十六进制的 14 字节化作十进制就是 20 字节那么从虚基表指针开始往下 5 个单位就是 A每个单位 4 个字节那么就刚好是 20 个字节就能找到 A. 9. 继承的总结 继承和组合 public 继承是一种 is-a 的关系。也就是说每个子类对象都是一个父类对象。 组合是一种 has-a 的关系。假设 B 组合了 A每个 B 对象中都有一个 A 对象。 什么是组合呢如下代码就是组合其中是 B 组合了 A class A{public:int _a;};class B{public:int _b;A a;};优先使用对象组合而不是类继承 。 继承允许我们根据父类的实现来定义子类的实现。这种通过生成子类的复用通常被称为白箱复用(white-box reuse)。术语 “白箱” 是相对可视性而言在继承方式中父类的内部细节对子类可见 。继承一定程度破坏了父类的封装父类的改变对子类有很大的影响。子类和父类间的依赖关系很强耦合度高。 对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。这种复用风格被称为黑箱复用(black-box reuse)因为对象的内部细节是不可见的。对象只以 “黑箱” 的形式出现。组合类之间没有很强的依赖关系耦合度低。 优先使用对象组合有助于我们保持每个类被封装。 实际尽量多去用组合。组合的耦合度低代码维护性好。 不过继承也有用武之地的有些关系就适合继承那就用继承另外要实现多态也必须要继承。类之间的关系可以用继承可以用组合就用组合。 二、多态 1. 多态的概念 多态的概念 通俗来说就是多种形态具体点就是去完成某个行为当不同的对象去完成时会产生出不同的状态。 比如买票这个行为当普通人买票时是全价买票学生买票时是半价买票军人买票时是优先买票。 2. 多态的定义及实现 多态是在不同继承关系的类对象去调用同一函数产生了不同的行为。比如 Student 继承了 Person。Person 对象买票全价Student 对象买票半价。 1多态的构成条件 那么在继承中要构成多态还有两个条件 必须通过父类的指针或者引用调用虚函数被调用的函数必须是虚函数且子类必须对父类的虚函数进行重写 我们先简单看一下多态的使用如以下代码 class Person{// 让 BuyTicket 成为虚函数 public:virtual void BuyTicket(){cout 买票-全价 endl;}};class Student : public Person{// 对 BuyTicket 进行重写public:virtual void BuyTicket(){cout 买票-半价 endl;}};// 父类的指针或者引用调用//void func(Person p)void func(Person* pa){pa-BuyTicket();}下面开始多态的调用如下结果 如上就是多态的简单使用下面开始详细介绍多态的条件。 2虚函数 虚函数 即被 virtual 修饰的类成员函数称为虚函数。 如下代码中的 BuyTicket 函数 class Person{public:virtual void BuyTicket(){cout 买票-全价 endl;}};3虚函数的重写 虚函数的重写(覆盖)子类中有一个跟父类完全相同的虚函数(即子类虚函数与父类虚函数的返回值类型、函数名字、参数列表完全相同)称子类的虚函数重写了父类的虚函数。 如下段代码中子类 Student 类对 BuyTicket 函数完成了重写 class Person{public:virtual void BuyTicket(){cout 买票-全价 endl;}};class Student : public Person{public:// void BuyTicket() // 子类对 BuyTicket 进行重写时也可以不加 virtualvirtual void BuyTicket(){cout 买票-半价 endl;}};在重写父类虚函数时子类的虚函数在不加 virtual 关键字时虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性)但是该种写法不是很规范不建议。这也和下面要说的析构函数的重写有一定的关联。 虚函数重写的两个例外 协变(父类与子类虚函数返回值类型不同) 子类重写父类虚函数时与父类虚函数返回值类型不同。即父类虚函数返回父类对象的指针或者引用子类虚函数返回子类对象的指针或者引用时称为协变。了解即可 如以下这段代码中也构成多态 class Person{public:virtual Person* BuyTicket(){cout 买票-全价 endl;return nullptr;}};class Student : public Person{public:virtual Student* BuyTicket(){cout 买票-半价 endl;return nullptr;}};析构函数的重写(父类与子类析构函数的名字不同) 如果父类的析构函数为虚函数此时子类析构函数只要定义无论是否加 virtual 关键字都与父类的析构函数构成重写虽然父类与子类析构函数名字不同。这样看起来违背了重写的规则其实不然这里可以理解为编译器对析构函数的名称做了特殊处理编译后析构函数的名称统一处理成 destructor . 如果在父类中没有加上 virtual 即析构函数不构成多态当下面这种情景时不能正确调用析构函数 // 析构函数不构成多态class Person{public:~Person(){cout ~Person() endl;}};class Student : public Person{public:~Student(){cout ~Student() endl;}};如上图当我们 new 的是一个子类对象将它赋值兼容给父类会发生切片操作此时我们释放 p 指针由于析构函数不构成多态因此只会调用父类的析构函数此时子类部分的空间就没有被释放就会发生内存泄漏。 当我们在父类的析构函数加上 virtual此时就构成多态了子类的析构加不加 virtual 都无所谓就是为了防止这种情况我们在子类中忘记对析构函数进行重写所以才会有上面的例外在子类中进行重写时可以不加 virtual所以我们在父类中加上 virtual 即可构成多态如下段代码 class Person{public:virtual ~Person(){cout ~Person() endl;}};class Student : public Person{public:~Student(){cout ~Student() endl;}};3override 和 final 从上面可以看出C 对函数重写的要求比较严格但是有些情况下由于疏忽可能会导致函数名字母次序写反而无法构成重载而这种错误在编译期间是不会报出的只有在程序运行时没有得到预期结果才来 debug 会得不偿失因此C11提供了 override 和 final 两个关键字可以帮助用户检测是否重写。 final修饰虚函数表示该虚函数不能再被重写 如下段代码 override检查子类虚函数是否重写了父类某个虚函数如果没有重写编译报错。 如下段代码 此时将B类中的func函数的返回类型改为 void 即可通过编译。 4重载、覆盖(重写)、隐藏(重定义) 重载、覆盖(重写)、隐藏(重定义)的对比如下图所示 3. 抽象类 1概念 在虚函数的后面写上 0 则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类也叫接口类抽象类不能实例化出对象。子类继承后也不能实例化出对象只有重写纯虚函数子类才能实例化出对象。纯虚函数规范了子类必须重写另外纯虚函数更体现出了接口继承。 class A{public:virtual void func() 0{cout A::func() endl;}};class B : public A{public:virtual void func(){cout B::func() endl;}};class C : public A{public:virtual void func(){cout C::func() endl;}};如上段代码A类是抽象类不能实例化出对象B类和C类继承了A类并完成重写 func 函数所以B类和C类可以实例化对象下面我们简单使用一下 2接口继承和实现继承 普通函数的继承是一种实现继承子类继承了父类函数可以使用函数继承的是函数的实现。 虚函数的继承是一种接口继承子类继承的是父类虚函数的接口目的是为了重写达成多态继承的是接口。所以如果不实现多态不要把函数定义成虚函数。 4. 多态的原理 1虚函数表 我们先看一下下面这个类的大小是多少 class A{public:virtual void Func(){cout Func() endl;}private:int _a 3;};根据我们以前学的知识成员函数不占A类的空间而是放在公共代码区而成员变量则根据内存对齐计算大小所以 sizeof(A) 4这样算对吗我们看一下结果 如上图答案是 8为什么会是 8 呢我们实例化一个对象出来观察它里面到底有什么 通过上图我们发现除了 _a 成员还多一个 __vfptr 放在对象的前面(注意有些平台可能会放到对象的最后面这个跟平台有关)对象中的这个指针我们叫做虚函数表指针(v代表virtualf代表function)。一个含有虚函数的类中都至少都有一个虚函数表指针因为虚函数的地址要被放到虚函数表中虚函数表也简称虚表。那么子类中这个表放了些什么呢我们接着往下分析 我们写一个 Base 类Derive 类继承BaseBase 类中Func1 和 Func2 是虚函数Func3 不是虚函数 Derive 中重写 Func1函数如下段代码 class Base{public:virtual void Func1(){cout Base::Func1() endl;}virtual void Func2(){cout Base::Func2() endl;}void Func3(){cout Base::Func3() endl;}private:int _b 1;};class Derive : public Base{public:virtual void Func1(){cout Derive::Func1() endl;}private:int _d 2;};下面我们实例化 b 对象和 d 对象 int main(){Base b;Derive d;return 0;}然后我们通过调试窗口观察对象中的内存 我们看到两个对象的虚函数指针是不一样我们再进一步观察虚函数指针中虚表的内容 通过观察和测试我们发现了以下几点问题 子类对象 d 中也有一个虚表指针d 对象由两部分构成一部分是父类继承下来的成员和虚表指针另一部分是自己的成员。父类 b 对象和子类 d 对象虚表是不一样的这里我们发现 Func1完成了重写所以 d 的虚表中存的是重写的 Derive::Func1 的地址所以虚函数的重写也叫作覆盖覆盖就是指虚表中虚函数地址的覆盖。重写是语法的叫法覆盖是原理层的叫法。另外 Func2 继承下来后是虚函数所以放进了虚表Func3 也继承下来了但是不是虚函数所以不会放进虚表。虚函数表本质是一个存虚函数指针的指针数组一般情况这个数组最后面放了一个nullptr。总结一下子类的虚表生成 a.先将父类中的虚表内容拷贝一份到子类虚表中 b.如果子类重写了父类中某个虚函数用子类自己的虚函数覆盖虚表中父类的虚函数 c.子类自己新增加的虚函数按其在子类中的声明次序增加到子类虚表的最后。 2多态的原理 有了上面的基础我们就可以分析一下多态的原理了 首先我们有以下两个类实现的多态 class Base{public:virtual void Func1(){cout Base::Func1() endl;}private:int _b 1;};class Derive : public Base{public:virtual void Func1(){cout Derive::Func1() endl;}private:int _d 2;};void Test(Base* pa){pa-Func1();}接下来我们分别使用Base和Derive实例化出对象 b 和 d再调用 Test 函数 int main(){Base b;Test(b);Derive d;Test(d);return 0;}下面我们从汇编的角度分析多态的原理如下图 从上图可以看出多态调用是运行时去虚表里面找到函数地址确定地址再调用。 但如果是对象调用如下代码就不构成多态我们同样在汇编角度分析 void Test(Base pa){pa.Func1();}int main(){Base b;Test(b);Derive d;Test(d);return 0;}从上图可以看出普通调用是编译链接时确定地址。 所以我们要达到多态有两个条件一个是虚函数覆盖一个是对象的指针或引用调用虚函数其中虚函数覆盖就不多说了 父类的指针或引用接收对象的指针或引用调用虚函数本质就是父类指针指向子类对象中切割出来父类的那一部分然后再取虚函数指针找到虚函数的地址。 那么我们使用对象调用为什么不能实现多态呢其实使用子类对象赋值给父类对象会切割出子类对象中父类那一部分成员拷贝给父类但是不会拷贝虚函数指针。为什么呢我们假设子类对象会拷贝虚函数表指针给父类对象我们看一下以下代码 Person* p new Person;Student s;*p s;delete p; 此时出现的问题就是多态调用指向父类调用的不一定是父类的虚函数了因为我们中间将 s 赋给了 *p现在 p 中的虚函数指针是 s 的所以这种方法不可取。 3动态绑定与静态绑定 静态绑定又称为前期绑定(早绑定)在程序编译期间确定了程序的行为也称为静态多态比如函数重载动态绑定又称后期绑定(晚绑定)是在程序运行期间根据具体拿到的类型确定程序的具体行为调用具体的函数也称为动态多态。 5. 虚函数和虚表存在于哪里 虚函数和虚表存在于哪里有人会说虚函数存在虚表虚表存在对象中。但是上面的回答的错误的。 想要知道虚函数和虚表存在于哪里我们可以打出各个区域的地址观察观察虚函数和虚表离哪个区域比较近下面我们开始验证如下段代码 class Base{public:virtual void func1(){cout Base::func1 endl;}virtual void func2(){cout Base::func2 endl;}private:int a;};void func(){cout void func() endl;}int main(){Base b1;static int a 0;int b 0;int* p1 new int;const char* p2 hello;printf(静态区:%p\n, a);printf(栈:%p\n, b);printf(堆:%p\n, p1);printf(代码段/常量区:%p\n, p2);printf(虚表:%p\n, *((int*)b1));printf(虚函数地址:%p\n, Base::func1);printf(普通函数地址:%p\n, func);return 0;}运行结果如下 我们可以看到在 vs2019 中虚表和虚函数的地址都是离代码段/常量区最近的所以我们认为在 vs2019 中它们是在代码段中的。 6. 单继承中的虚函数表 需要注意的是在单继承和多继承关系中下面我们去关注的是子类对象的虚表模型因为父类的虚表模型前面我们已经看过了没什么需要特别研究的。我们这里就只看单继承的中的虚函数表。 例如有以下代码 class Base {public:virtual void func1() { cout Base::func1 endl; }virtual void func2() { cout Base::func2 endl; }private:int a;};class Derive :public Base {public:virtual void func1() { cout Derive::func1 endl; }virtual void func3() { cout Derive::func3 endl; }virtual void func4() { cout Derive::func4 endl; }private:int b;};int main(){Base b;Derive d;return 0;}我们通过监视窗口观察子类对象中的虚表模型 观察上图中的监视窗口中我们发现看不见 func3 和 func4。这里是编译器的监视窗口故意隐藏了这两个函数也可以认为是他的一个小 bug。那么我们如何查看 d 的虚表呢下面我们使用代码打印出虚表中的函数。 class Base {public:virtual void func1() { cout Base::func1 endl; }virtual void func2() { cout Base::func2 endl; }private:int a;};class Derive : public Base {public:virtual void func1() { cout Derive::func1 endl; }virtual void func3() { cout Derive::func3 endl; }virtual void func4() { cout Derive::func4 endl; }private:int b;};// typedef 函数指针类型typedef void (*VFUNC)();void PrintVFT(VFUNC* a){for (size_t i 0; a[i] ! 0; i){printf([%d]:%p-, i, a[i]);VFUNC f a[i];f(); // 相当于调(*f)(); 调函数指针对应的函数}}int main(){Base b;PrintVFT((VFUNC*)(*((int*)b)));cout endl;Derive d;PrintVFT((VFUNC*)(*((int*)d)));return 0;}打印的结果如下 此时我们就可以看到 d 对象中的虚函数了。
http://www.zqtcl.cn/news/17991/

相关文章:

  • 布吉网站建设哪家效益快三网站建设
  • 云南网站制作一条龙个人网页开发毕业设计
  • 网站建设注册什么公司好免费网站空间免费主机
  • 网站维护费计入什么科目pc网站建设需要提供哪些资料
  • 做电影网站要怎么拿到版权简述一下网站的设计流程
  • 昆山周市建设局网站wordpress 论坛模版
  • 特优项目网站建设方案网站建设百度帖吧
  • 上海市工程建设信息网官方网站深圳电子厂
  • 手机模板网站模板下载什么是网络营销推广
  • 公司网站百度排名没有了地推网
  • 网站的开发工具和运行环境广西建设厅网站绿色建筑标识
  • 做国外网站有哪些网站开发上海工资
  • 线切割加工东莞网站建设技术支持查关键词排名软件
  • 用html5做网站的优点南京广告宣传公司seo
  • 网站开发子孙账号网易企业邮箱收费多少
  • 怎么做素材设计网站wordpress 子模板
  • 北京做网站开发公司wordpress底部怎么改
  • aspx网站 整站抓取wordpress批量导入
  • 网站优化公司哪个好网页模版
  • 设计网站公司 讲湖南岚鸿h5视频怎么制作教学
  • 电子商务网站建设步骤一般为怎么做网站推销产品
  • 泰州企业模板建站北京办公室装修
  • idc自动续费网站源码手机棋牌app软件开发
  • 闸北集团网站建设如何制作一个小程序
  • 网站开发方案目录网站模板怎么样
  • 北京网站搭建开发建设电子商务网站总体设计阶段
  • 响应式个人网站模板网络整合营销的目的是什么
  • google建网站镇江网站推广优化
  • 优惠券精选网站怎么做网站空间租用费用
  • 新一站保险网智慧团建网站首页