【C++】 多态与虚函数

【C++】动态多态与虚函数 本文【C++】动态多态与虚函数 主要讲述了C++中的多态、虚函数、刨析了多态的底层实现和做了什么、虚析构、纯虚函数和抽象类。以详细的代码示例和例子,使我们学习相关的知识更加通俗易懂。 有感兴趣的小伙伴可以关注一下噢! 阅读详情

总结1——多态

(1) 通过基类的指针既可以访问基类的成员,也可以访问派生类的成员。

(2) 试图使用不变的代码来实现可变的算法,让父类的指针有 “多种形态”。

(2) 用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。

构成多态的条件:

  • 必须存在继承关系;
  • 继承关系中必须有同名的虚函数,并且它们是覆盖关系(函数原型相同)。
  • 存在基类指针,通过该指针调用虚函数。

总结2——什么时候声明虚函数

先看成员函数所在的类是否会作为基类。
再看成员函数在类的继承后有无可能被更改功能。

如果希望更改其功能的,一般应该将它声明为虚函数。如果成员函数在类被继承后功能不需修改,或派生类用不到该函数,则不要把它声明为虚函数。

总结3——虚函数的注意事项。

(1) 只需要在虚函数的声明处加上 virtual 关键字,函数定义处可以加也可以不加。
(2) 为了方便,可以只将基类中的函数声明为虚函数,这样所有派生类中具有遮蔽(覆盖)关系的同名函数都将自动成为虚函数。
(3) 当在基类中定义了虚函数时,如果派生类没有定义新的函数来遮蔽此函数,那么将使用基类的虚函数。
(4) 只有派生类的虚函数覆盖基类的虚函数(函数原型相同)才能构成多态(通过基类指针访问派生类函数)

例如基类虚函数的原型为

virtual void func();

派生类虚函数的原型为

virtual void func(int);

那么当基类指针 p 指向派生类对象时,语句

p -> func(100);

将会出错,而语句

p -> func();

将调用基类的函数。

(5) 构造函数不能是虚函数

对于基类的构造函数,它仅仅是在派生类构造函数中被调用,这种机制不同于继承。也就是说,派生类不继承基类的构造函数,将构造函数声明为虚函数没有什么意义。

(6) 析构函数可以声明为虚函数,而且有时候必须要声明为虚函数

01 虚函数的简介

由于编写代码的时候并不能确定被调用的是基类的函数还是哪个派生类的函数,所以被成为 “虚” 函数。

用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。

这种技术可以让父类的指针有 “多种形态”,这是一种泛型技术。

所谓泛型技术,就是试图使用不变的代码来实现可变的算法。

虚函数主要通过V-Table虚函数表来实现,该表主要包含一个类的虚函数的地址表,可解决继承、覆盖的问题。

当使用一个父类的指针去操作一个子类时,虚函数表就像一个地图一样,可指明实际所应该调用的函数。

(每一个virtual函数的class都有一个相应的 vtbl,当对象调用某一 virtual 函数,实际被调用的函数取决于该对象的 vptr 所指的那个 vtbl ——编译器在其中寻找适当的函数指针。)

防止多重派生时,使用指针调用同名函数时已基类函数(父类)为准。

02 虚函数的核心概念

某基类中声明为 virtual 并在一个或多个派生类中重新定义的成员函数叫做虚函数。

03 虚函数的核心作用

(1) 实现动态联编,在函数运行阶段动态的选择合适的成员函数。

(2) 在定义了虚函数后,可实现在派生类中对虚函数进行重写,从而实现统一的接口和不同的执行过程。

通过三个虚函数的应用实例来说明虚函数的主要作用。

🌰 继承关系中非虚函数
#include <iostream>

class Base{
public:
    Base(){};
    ~Base(){};
    void show(void){
        std::cout << "基类成员函数 show ......" << std::endl;
    }
};

class Derive:public Base{
public:
    Derive(){};
    ~Derive(){};
    void show(void){
        std::cout<< "派生类成员函数 show ......" << std::endl;    
    }        
};

int main(){
    // 基类实例化
    Base atr;
    // 派生类实例化
    Derive btr;
    
    // 定义基类指针
    Base *ptr;
    ptr = &atr;
    ptr->show();
    
    ptr = &btr;
    ptr->show();
    return 0;
}

输出结果

基类 show ......
基类 show ......
Note

即使 ptr 指向 B 对象后,第二个 show() 的结果也并不是 “I am B!”,

主要原因该程序使用的是静态联编,而静态联编选择函数是基于指向对象的指针类型,而 ptr 是指向 Base 的指针,因此也会一直调用 Base 的成员函数 show()。

🌰-1 继承关系中虚函数
#include <iostream>

class Base{
public:
    Base(){
			std::cout << "Base Constructor Function" << std::endl;
		}
    ~Base(){
			std::cout << "Base Destructor Function" << std::endl;
		}
    virtual void show(void){
        std::cout << "基类成员函数 show ......" << std::endl;
    }
};

class Derive:public Base{
public:
    Derive(){
			std::cout << "Derive Constructor Function" << std::endl;
		}
    ~Derive(){
			std::cout << "Derive Destructor Function" << std::endl;
		}
    void show(void){
        std::cout<< "派生类成员函数 show ......" << std::endl;    
    }        
};

int main(){
    // 基类实例化
    Base base;
    // 定义基类指针
    Base *ptr_base;
    ptr_base= &base;
    ptr_base->show();
    std::cout << "----------------------------" << std::endl;
    // 派生类实例化
    Derive* pb = new Derive(); 
    pb->show();
    delete pb;

    return 0;
}

输出结果

Base Constructor Function
基类成员函数 show ......
----------------------------
Base Constructor Function
Derive Constructor Function
派生类成员函数 show ......
Bae Destructor Function
Base Destructor Function
🌰-2 继承关系中虚函数
#include <iostream>

class Base{
public:
    Base(){
			std::cout << "Base Constructor Function" << std::endl;
		}
    virtual ~Base(){
			std::cout << "Base Destructor Function" << std::endl;
		}
    virtual void show(void){
        std::cout << "基类成员函数 show ......" << std::endl;
    }
};

class Derive:public Base{
public:
    Derive(){
			std::cout << "Derive Constructor Function" << std::endl;
		}
    ~Derive(){
			std::cout << "Derive Destructor Function" << std::endl;
		}
    void show(void){
        std::cout<< "派生类成员函数 show ......" << std::endl;    
    }        
};

int main(){
    // 基类实例化
    Base base;
    // 定义基类指针
    Base *ptr_base;
    ptr_base= &base;
    ptr_base->show();
    std::cout << "----------------------------" << std::endl;
    // 派生类实例化
    Derive* pb = new Derive(); 
    pb->show();
    delete pb;

    return 0;
}

输出结果

Base Constructor Function
基类成员函数 show ......
----------------------------
Base Constructor Function
Derive Constructor Function
派生类成员函数 show ......
Derive Destructor Function
Base Destructor Function
Note

在基类 Base 中对 show() 这一成员函数变为 virtual 虚函数后,会采用动态编译,只有调用它时才用根据它的对象类型去匹配对应的函数体。

🌰 非继承关系中虚函数
#include<iostream>

class A{
public:
    A(){};
    ~A(){};
    virtual void show(void){
        std::cout << "I am A!"<< std::endl;
    }
};
class B{
public:
    B(){};
    ~B(){};
    virtual void show(void){
        std::cout << "I am B!" << std::endl;    
    }        
};

int main(){
    std::cout << "hello world"<< std::endl;
    A atr, *ptr;
    B btr;
    
    ptr = &atr;
    ptr->show();
    
    ptr = (A*)&btr;
    ptr->show();
    
    system("pause>nul");
}
小结

(1) 在使用继承的方式实现运行时多态时,基类需要将与派生类相同函数名的函数加上 virtual 关键字,这样才可以在运行时精准识别出子类的虚函数。

(2) 如果要不通过继承关系也实现出运行时多态的效果,则需要将两个不同类的同名函数都加上 virtual 关键字;同时,需要将定义的指针指向其他对象时,要进行强制类型转换。(因为两个类已经没有继承关系了,不能通过赋值兼容规则进行自动转换,所以要强制转化。)

(3) 带有多态性质的基类均应该声明一个virtual析构函数。同时如果任一class带有任何virtual函数,它就应该拥有一个virtual析构函数。

(4) 当 class 的设计目的如果不是作为 base class 使用,或不是为了具备多态性,则就不该声明 virtual 析构函数。

因为如果 class 中含有 virutal 函数会使得该 class 的体积增加,因为添加一个vptr(virtual table pointer)会增加其 class 大小达 50%-100%。

拓展问题:

(1) 为什么调用普通函数比调用虚函数的效率高?

因为普通函数是静态联编的,而调用虚函数是动态联编的。
联编的作用:程序调用函数,编译器决定使用哪个可执行代码块。(所谓联编就是将函数名和函数体的程序连接到一起的过程)
静态联编 :在编译的时候就确定了函数的地址,然后call就调用了。

静态联编本质是系统用实参与形参进行匹配,对于重名的重载函数根据参数上的差异进行区分,然后进行联编,从而实现编译时的多态。函数的选择基于指向对象的指针类型或者引用类型。

动态联编 : 首先需要取到对象的首地址,然后再解引用取到虚函数表的首地址后,再加上偏移量才能找到要调的虚函数,然后call调用。

动态联编本质上是运行阶段执行的联编,当程序调用某一个函数时,系统会根据当前的对象类型去寻找和连接其程序的代码。函数的选择基于对象的类型。

(2) 为什么要用虚函数表(存函数指针的数组)?

同一个类的多个对象的虚函数表是同一个,所以这样就可以节省空间,一个类自己的虚函数和继承的虚函数还有重写父类的虚函数都会存在自己的虚函数表。

同时,虚函数表本质是一个地图导航,可以清楚告诉一个想要操作子类的父类指针到底该使用哪个函数。

(3) 为什么要把基类的析构函数定义为虚函数?
C++ 虚析构函数
构造函数不能是虚函数
原因1

派生类不能继承基类的构造函数,将构造函数声明为虚函数没有意义。

原因2

C++ 中的构造函数用于在创建对象时进行初始化工作,在执行构造函数之前对象尚未创建完成,虚函数表尚不存在,也没有指向虚函数表的指针,所以此时无法查询虚函数表,也就不知道要调用哪一个构造函数。

析构函数可以是或有时必须是析构函数

析构函数用于在销毁对象时进行清理工作,可以声明为虚函数,而且有时候必须要声明为虚函数。

在用基类操作派生类时,为了防止执行基类的析构函数,不执行派生类的析构函数。

因为这样的删除只能够删除基类对象, 而不能删除子类对象, 形成了删除一半形象, 会造成内存泄漏。

🌰 析构函数可以是或有时必须是析构函数
#include <iostream>

class Base{
public:
    Base(){
        std::cout << "基类构造函数 ..." << std::endl;
        base_ptr = new int[100];
    }
    ~Base(){
        std::cout << "基类析构函数 ......" << std::endl;
        delete[] base_ptr;
    }
protected:
    int* base_ptr;
};

class Derive:public Base{
public:
    Derive(){
        std::cout << "Derive 构造函数 ..." << std::endl;
        derive_ptr = new int[100];
    }
    ~Derive(){
        std::cout<< "Derive 析构函数 ......" << std::endl;
        delete[] derive_ptr;
    }   
private:
    int* deprive_ptr;
};

int main(){
    Base* pb = new Derive();
    delete pb;
    
    std::cout << "---------------------" << std::endl;
    
    Derive* pd = new Derive();
    delete pd;
    
    return 0;
}

输出结果

基类构造函数 ...
派生类构造函数 ...
基类析构函数 ......
---------------------
基类构造函数 ...
派生类构造函数 ...
派生类析构函数 ......
基类析构函数 ......

上栗中定义了两个类,基类 Base 和派生类 Derive,它们都有自己的构造函数和析构函数。

在构造函数中,会分配 100 个 int 类型的内存空间;在析构函数中,会把这些内存释放掉。

pb、pd 分别是基类指针和派生类指针,它们都指向派生类对象,最后使用 delete 销毁 pb、pd 所指向的对象。

从运行结果可以看出,语句delete pb;只调用了基类的析构函数,没有调用派生类的析构函数;而语句delete pd;同时调用了派生类和基类的析构函数。

不调用派生类的析构函数会导致 derive_ptr 指向的 100 个 int 类型的内存空间得不到释放;除非程序运行结束由操作系统回收,否则就再也没有机会释放这些内存。这是典型的内存泄露。

(1) 为什么 delete pb;不会调用派生类的析构函数呢?

因为这里的析构函数是非虚函数,通过指针访问非虚函数时,编译器会根据指针的类型来确定要调用的函数;

也就是说,指针指向哪个类就调用哪个类的函数。

pb 是基类的指针,所以不管它指向基类的对象还是派生类的对象,始终都是调用基类的析构函数。

(2) 为什么delete pd;会同时调用派生类和基类的析构函数呢?

pd 是派生类的指针,编译器会根据它的类型匹配到派生类的析构函数,在执行派生类的析构函数的过程中,又会调用基类的析构函数。

派生类析构函数始终会调用基类的析构函数,并且这个过程是隐式完成的。

更改上面的代码,将基类的析构函数声明为虚函数:

#include <iostream>

class Base{
public:
    Base(){
        std::cout << "基类构造函数 ..." << std::endl;
        base_ptr = new int[100];
    }
    virtual ~Base(){
        std::cout << "基类析构函数 ......" << std::endl;
        delete[] base_ptr;
    }
protected:
    int* base_ptr;
};

class Derive:public Base{
public:
    Derive(){
        std::cout << "派生类构造函数 ..." << std::endl;
        derive_ptr = new int[100];
    }
    ~Derive(){
        std::cout<< "派生类析构函数 ......" << std::endl;
        delete[] derive_ptr;
    }   
private:
    int* deprive_ptr;
};

int main(){
    Base* pb = new Derive();
    delete pb;
    
    std::cout << "---------------------" << std::endl;
    
    Derive* pd = new Derive();
    delete pd;
    
    return 0;
}

输出结果

基类构造函数 ...
派生类构造函数 ...
派生类析构函数 ......
基类析构函数 ......
---------------------
基类构造函数 ...
派生类构造函数 ...
派生类析构函数 ......
基类析构函数 ......
将基类的析构函数声明为虚函数发生了什么变化?

将基类的析构函数声明为虚函数后,派生类的析构函数也会自动成为虚函数。

这个时候编译器会忽略指针的类型,而根据指针的指向来选择函数。

将基类的析构函数声明为虚函数,指针指向哪个类的对象就调用哪个类的函数。

pb、pd 都指向了派生类的对象,所以会调用派生类的析构函数,继而再调用基类的析构函数。如此一来也就解决了内存泄露的问题。

在实际开发中,一旦定义了析构函数,就是希望在对象销毁时用它来进行清理工作,比如释放内存、关闭文件等,如果这个类又是一个基类,那么,就必须将该析构函数声明为虚函数,否则就有内存泄露的风险。

也就是说,大部分情况下都应该将基类的析构函数声明为虚函数。

注意,这里强调的是基类,如果一个类是最终的类,那就没必要再声明为虚函数了。

这里子类的析构函数重写了父类的析构函数,虽然子类和父类的析构函数名不一样,

但是,编译器对析构函数做了特殊处理,在内部子类和父类的析构函数名是一样的。

所以,如果不把父类的析构函数定义成虚函数,就不构成多态。

由于父类的析构函数隐藏了子类的析构函数,所以只能调到父类的析构函数。

但是,若把父类的析构函数定义成虚函数,那么,调用时就会直接调用子类的析构函数。

由于子类析构先要去析构父类,再析构子类,这样就会把父类和继承的子类都析构。

(4) 虚函数可以是内联的吗?

要多态的时候不内联,不多态的时候(也就是非指针、引用,也就是传值)可以内联。

(5) 多态的栗子

🌰

#include <iostream>

// 基类Base
class Base{
public:
    virtual void func(){
        std::cout<<"void Base::func()"<<std::endl;
    }
    virtual void func(int){
        std::cout<<"void Base::func(int)"<<std::endl;
    }
};

// 派生类 Derived
class Derived: public Base{
public:
    void func(){
        std::cout<<"void Derived::func()"<<std::endl;
    }
    void func(char *){
        std::cout<<"void Derived::func(char *)"<<std::endl;
    }
};

int main(){
    Base *p = new Derived();
    
    std::cout << "p -> func() 输出:" << std::endl;
    p -> func();  
    std::cout << std::endl;
    
    std::cout << "p -> func(10) 输出:" << std::endl;
    p -> func(10); 
    std::cout << std::endl;
    
    std::cout << "p -> func("hello world") 输出:" << std::endl;
    p -> func("hello world");  

    return 0;
}

输出结果

p -> func() 输出:
void Derived::func()

p -> func(10) 输出:
void Base::func(int)

p -> func("hello world") 输出:
compile error

在基类 Base 中,将void func()声明为虚函数,这样派生类 Derived 中的void func()就会自动成为虚函数。p 是基类 Base 的指针,但是指向了派生类 Derived 的对象。

(1) 语句

p -> func();

调用的是派生类的虚函数,构成了多态。

(2) 语句

p -> func(10);

调用的是基类的虚函数,因为派生类中没有函数覆盖它。

(3) 语句

p -> func("hello world");

编译错误,因为通过基类的指针只能访问从基类继承过去的成员,不能访问派生类新增的成员。

参考链接

原文链接1:https://blog.youkuaiyun.com/weixin_38537639/article/details/117821816

原文链接2:http://c.biancheng.net/cplus/polymorphism/

【C++入门】虚函数与多态 C++ 是一种功能强大的编程语言,以其面向对象编程(OOP)特性而闻名。虚函数和多态是 C++ 面向对象编程中的两个重要概念,它们使得代码更灵活、更具扩展性。本篇文章将介绍虚函数与多态,包括其定义、使用方法及其在实际编程中的作用。虚函数和多态是 C++ 中面向对象编程的重要特性,通过虚函数可以实现多态性,使得代码更加灵活和可扩展。虚函数允许在运行时通过基类指针或引用调用子类的重写方法,而纯虚函数则强制派生类实现某些方法,使得抽象类无法实例化。 阅读详情

相关推荐

AppleAccount注册之生成sign

根据日志发现:签名来自于AuthKit的-[AKAppleIDServerResourceLoadDelegate signRequest:withCompletionHandler:]的一个block,这个库是放在共享缓存库里的,找到提前准备好的IDA文件,先去找主方法,根据分析IDA,最后找到了实际生成签名的方法:t1。,接受五个参数,context(之前讲的获取到的客户端证书),bytes(待加密的body字节),length(字节长度),以及两个接受结果的参数,直接进这个方法看,

2503_90751938的博客 1002

C++专题:多态性与虚函数(详细!)

对C++的多态性和虚函数进行了详细介绍

m0_70983574的博客 2693

LiveKit 本地部署实战:从零搭建安全实时通信环境(Caddy+HTTPS)

本文详细介绍了如何从零开始搭建LiveKit本地部署环境,结合Caddy服务器实现HTTPS安全通信。通过环境准备、证书生成、服务配置到前端客户端集成的完整流程,帮助开发者快速构建实时音视频应用,特别适合需要安全实时通信的场景。

weixin_29227585的博客 673

C++多态与虚函数

文章目录C++多态和虚函数快速入门教程借助引用也可以实现多态多态的用途C++虚函数注意事项以及构成多态的条件构成多态的条件什么时候声明虚函数C++虚析构函数的必要性C++纯虚函数和抽象类详解关于纯虚函数的几点说明C++虚函数表精讲教程,直戳多态的实现机制C++ typeid运算符:获取类型信息1) 原型:const char* name() const;2) 原型:bool before (const type_info& rhs) const;3) 原型:bool operator== (cons

qq_41854911的博客 1904

别再手动写ZPL了!用C#和斑马官方SDK搞定ZT410 RFID打印机(附中文乱码解决方案)

本文详细介绍了如何使用C#和斑马官方SDK驱动ZT410 RFID打印机,解决中文乱码和RFID数据写入等常见问题。通过实战指南,开发者可以快速掌握从基础连接到高级调试的全流程,提升打印效率和可靠性。特别适用于物流、零售和资产管理领域的应用。

weixin_29267307的博客 222

保姆级教程:用rosbag录制和回放你的第一个ROS机器人数据(附C++/Python代码)

本文提供了一份详细的ROS机器人数据录制与回放教程,涵盖从命令行操作到C++/Python编程实现的全流程。通过rosbag工具,开发者可以高效记录和回放机器人运行时的传感器数据和控制指令,适用于故障复现、算法调试等多种场景。教程还包含高级技巧如时间同步和大文件处理,帮助用户快速掌握ROS数据管理核心技能。

weixin_29313239的博客 283

C++ 虚函数与多态性

一、 参考文献: 【1】C++:为什么在继承关系中,父类的析构函数最好定义为虚函数?:https://blog.youkuaiyun.com/han8040laixin/article/details/81704165

灰太狼的小秘密 1399

RAG的“诊断艺术”:从测试集结果倒追根源,精准优化检索、排序与生成

当RAG应用给出一个糟糕的答案时,开发者的第一反应可能是:“我的Prompt写得不够好?”这种基于“感觉”的猜测往往是低效的。通过构建一个包含黄金上下文信息的测试集,我们可以像一位经验丰富的医生一样,对RAG系统的各个“器官”进行独立的“健康检查”。一个用于RAG诊断的测试集,除了问题和答案,还需要包含中间环节的“黄金标准”。如果你的RAG流程包含Re-ranker,那么在评估完初期的召回后,需要单独评估Re-ranker的效果。RAG的优化是一个持续的过程,应该形成一个闭环。的文档块尽可能多地召回。

kakaZhui的博客 153

C++:虚函数与多态

本文介绍了C++中的虚函数与多态的概念,并介绍了虚函数与多态的实现原理。

2301_79959126的博客 1484

人工智能算法面试大总结-总目录

涉及秋招、春招、社招

啥都生的博客 2万+

7、RNA 二级结构预测:包含接吻发夹基序的新策略

本文提出三种用于预测RNA二级结构中接吻发夹基序的新策略,结合规范化规则与非歧义动态规划,分别在时间与空间复杂度之间进行权衡。策略A以O(n⁴)时间和O(n²)空间实现高效预测;策略B通过存储次优结果扩大搜索空间,空间复杂度升至O(n³);策略C全面探索组合可能,时间复杂度为O(n⁵),但保持O(n²)空间。实验表明不同策略适用于不同复杂度的序列,为RNA结构预测提供了灵活且可扩展的解决方案。

j7k8l的博客 132

C++ 多态与虚函数

文章目录1. 多态的概念多态的性质多态的分类2. 虚函数实现动态多态性多态的构成条件虚函数虚函数重写的两个例外(不是特定规则)C++11 override 和 final3.纯虚函数与抽象类纯虚函数:抽象类接口继承和实现继承4.多态的原理虚函数表动态绑定与静态绑定(关联)5.单继承和多继承关系中的虚函数表 多态的概念 多态的定义及实现 抽象类 多态的原理 单继承和多继承关系中的虚函数表 继承和多态常见的面试问题 1. 多态的概念 多态的性质 多态性是面向对象程序设计的一个重要特性。 多态本意:一个事物有

e我所欲也的博客 1309

Python与CAD系列基础篇(二)创建点和直线并修改样式

①通过pyautocad连接AutoCAD进行处理②通过ezdxf处理dxf格式文件。创建和编辑点和直线的方法,并演示如何修改它们的样式、颜色和线型。

weixin_43894929的博客 3035

[cpp进阶]多态和虚函数

文章目录多态的概念 多态的概念 多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。 多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。 C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。 比如说: 买票这个行为,当普通人买票时,是全价买票;学生买票时,是半价买票;军人买票时是优先买票。 买票这一个行为,不同的人做就有不同的行为和结果,这就是多态。 ...

weixin_53027918的博客 1242

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

CPP多态性与虚函数

文章目录多态性与虚函数面向对象程序设计中的多态性派生类与基类对象之间的赋值虚函数虚析构函数纯虚函数(抽象类)虚函数与虚基类派生类中重定义基类中的重载函数虚函数动态绑定的实现原理 多态性与虚函数 面向对象程序设计中的多态性 多态性(polymorphism) 调用同一个函数名,根据需要实现不同的功能。 编译时的多态性:静态多态(函数重载、运算符重载) 运行时的多态性:动态多态(虚函数) 函数重载和运算符重载实现的多态性属于静态多态性,在程序编译时就能决定调用的是哪个函数。静态多态性又称编译时的多态性。静态

SongyangJi 1589

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

C++ 多态和虚函数

虚函数实现多态 #include <iostream> using namespace std; //基类People class People{ public: virtual void display(); //声明为虚函数 }; void People::display(){ cout<<"无业游民。"<<endl; } //派生类Teacher class Teacher: public People{ public: virtu

少说,多做。 5682

【C++】继承、虚函数、多态

详细介绍C++的继承、虚函数、多态以及虚函数表,并通过代码示例说明

weixin_40514381的博客 1459

C++虚函数与多态详解

虚函数与多态

君鼎的博客 1130

C++ 虚函数与多态

摘要: 多态是C++中通过虚函数实现的运行时动态绑定机制,允许基类指针或引用根据实际对象类型调用不同函数。实现多态需满足三个条件:继承关系、基类虚函数声明、通过基类指针/引用调用。

平平无奇的小甜菜 1031

深入研究C++多态与虚函数机制

多态的概念;多态的定义及实现:多态的构成条件、虚函数、虚函数的重写、虚函数重写的两个例外、override和final(C++11)、重载、覆盖(重写)、隐藏(重定义);抽象类:概念,接口继承和实现继承;多态的原理:虚函数表、多态的原理、动态绑定和静态绑定;单继承和多继承关系的虚函数表:单继承中的虚函数表、多继承中的虚函数表、菱形继承、菱形虚拟继承;继承和多态常见的面试问题:概念考察,问答题。

Russ_Leo的博客 1279

C++多态, 虚函数, 纯虚函数

多态:不同对象接收相同的消息产生不同的动作。多态包括编译时多态和运行时多态   运行时多态是:通过继承和虚函数来体现的。 编译时多态:运算符重载上。 封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。多态也有代码重用的功能,还有解决项目中紧耦合的问题,提高程序的可扩展性。C++实现多态的机制很简单,在继承体系下,将父类的某个函数...

yangxueyangxue的博客 971

C++的多态与虚函数

多态的作用:继承是子类使用父类的方法,而多态则是父类使用子类的方法。 在C++中,多态有两种,一种是函数重载,一种是虚函数。函数重载发生在编译的时候,它的函数参是不一样的。而虚函数是发生在运行的时候,它的函数原型式样的,依靠的是指针的指向。 有一篇非常好的文章介绍多态与虚函数。发一个链接在这里。 http://blog.youkuaiyun.com/augusdi/article/details

Thinking 3099

【C++】虚函数与多态

虚函数和多态是 C++ 中强大而重要的特性,它们为我们的编程带来了极大的灵活性和可扩展性。虚函数作为实现多态的关键,通过动态绑定机制,让程序在运行时能够根据对象的实际类型来调用正确的函数版本,就像一把万能钥匙,开启了多态编程的大门。多态则是 C++ 面向对象编程的核心体现之一,它分为静态多态和动态多态,其中动态多态通过虚函数和继承来实现,使得我们能够以统一的方式处理不同类型的对象,编写更加通用、可维护的代码。

大雨淅淅的博客 984
上一篇: 【Linux】一切皆文件
下一篇: 【C++11】final 与 override 关键字
Fourier 青年
博客等级 码龄9年 36粉丝 85原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值