C++继承,多态,虚函数表

文章通过C++代码示例解释了如何使用虚函数实现多态性,展示了从C++到C的翻译,讨论了虚表和运行时类型信息(RTTI)在类层次结构中的作用。同时,提到了静态和动态类型转换在多继承场景下的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、C++代码片段一:
#include <cstdio>
#include <cstdint>
#include <cstdlib>

class ISpeaker{
protected:
	size_t b;
public:
	ISpeaker( size_t _v )
		: b(_v) 
	{}
	virtual void speak() = 0;
};

class Dog : public ISpeaker {
public:
	Dog()
		: ISpeaker(0)
	{}
	//
	virtual void speak() override {
		printf("woof! %llu\n", b);
	}
};

class Human : public ISpeaker {
private:
	size_t c;
public:
	Human()
		: ISpeaker(1)
		, c(2)
	{}

	virtual void speak() override {
		printf("hello! %llu\n", c);
	}
};

int main( int argc, char** _argv ) {
	Human* pHuman = new Human();
	Dog* pDog = new Dog();
	//
	ISpeaker* speaker1 = (ISpeaker*)pHuman;
	ISpeaker* speaker2 = (ISpeaker*)pDog;
	//
	speaker2->speak();
	speaker1->speak();
	//
	return 0;
}
二、翻译后的C代码片段一:
#include <cstdio>
#include <cstdlib>
#include <cstdint>

extern "C" {

	struct SpeakerTable {
		void(* speak )( void* _ptr );
	};

	void __dog_speak( void* _ptr ) {
		uint8_t* p = (uint8_t*)_ptr;
		p+=sizeof(SpeakerTable*);
		size_t b = *((size_t*)p);
		printf("woof! %llu\n", b);
	}

	void __human_speak( void* _ptr ) {
		uint8_t* p = (uint8_t*)_ptr;
		p+=sizeof(SpeakerTable*);
		p+=sizeof(size_t);
		size_t b = *((size_t*)p);
		printf("hello! %llu\n", b);
	}

	const static SpeakerTable __dogSpeakTable = {
		__dog_speak
	};
	const static SpeakerTable __humanSpeakTable = {
		__human_speak
	};

	struct __ispeaker {
		const SpeakerTable* vt;
		size_t b;
	};

	struct __dog {
		const SpeakerTable* vt;
		size_t b;
	};

	struct __human {
		const SpeakerTable* vt;
		size_t b;
		size_t c;
	};

	__dog * createDog() {
		__dog* ptr = (__dog*)malloc(sizeof(__dog));
		ptr->vt = &__dogSpeakTable;
		ptr->b = 0;
		return ptr;
	}

	__human* createHuman() {
		__human* ptr = (__human*)malloc(sizeof(__human));
		ptr->vt = &__humanSpeakTable;
		ptr->b = 1;
		ptr->c = 2;
		return ptr;
	}

};

int main( int _argc, char** _argv ) {
    __dog* dog = createDog();
	__human* human = createHuman();
	//
	__ispeaker* speaker1 = (__ispeaker*)dog;
	__ispeaker* speaker2 = (__ispeaker*)human;
	//
	speaker1->vt->speak(speaker1);
	speaker2->vt->speak(speaker2);
	return 0;
}
三、C++代码片段二:
#include <cstdio>
#include <cstdint>
#include <cstdlib>

class IRunner {
private:
    size_t a;
public:
    IRunner()
        : a(0) 
    {
    }
    virtual void run() = 0;
};

class ISpeaker {
protected:
    size_t b;
public:
    ISpeaker(size_t _v)
        : b(_v)
    {}
    virtual void speak() = 0;
};

class Dog : public ISpeaker {
public:
    Dog()
        : ISpeaker(1)
    {}
    //
    virtual void speak() override {
        printf("woof! %llu\n", b);
    }
};

class RunnerDog : public IRunner, public Dog {
public:
    RunnerDog()
    {}

    virtual void run() override {
        printf("run with 4 legs\n");
    }
};

int main(int argc, char** _argv) {
    RunnerDog* pDog = new RunnerDog();
    Dog* simpleDog = new Dog();
    pDog->speak();
    { // 等价于
        ISpeaker* speaker1 = static_cast<ISpeaker*>(pDog);
        speaker1->speak();
    }

    ISpeaker* speaker = static_cast<ISpeaker*>(simpleDog);
    RunnerDog* runnerDog = dynamic_cast<RunnerDog*>(speaker);
    // RTTI 信息
    if (runnerDog) {
        runnerDog->run();
    }
    //
    // 子类 -> 基类 ( static_cast<>() )
    // 基类 -> 子类 ( dynamic_cast<>() )
    // 有可能变化
    // RunnerDog* runnerDog = (RunnerDog*)(speaker);
    return 0;
}
四、翻译后的C代码片段二:
#include <cstdio>
#include <cstdlib>
#include <cstdint>

extern "C" {

#define RTTI_INFORMATION

    struct RunnerTable {
        RTTI_INFORMATION
            void(*run)(void* _ptr);
    };

    struct SpeakerTable {
        RTTI_INFORMATION
            void(*speak)(void* _ptr);
    };

    void __dog_run(void* _ptr) {
        printf("run with 4 legs");
    }

    void __dog_speak(void* _ptr) {
        uint8_t* p = (uint8_t*)_ptr;
        p += sizeof(SpeakerTable*);
        size_t b = *((size_t*)p);
        printf("woof! %llu\n", b);
    }

    const static RunnerTable __dogRunnerTable = {
        RTTI_INFORMATION
        __dog_run
    };

    const static SpeakerTable __dogSpeakTable = {
        RTTI_INFORMATION
        __dog_speak
    };

    struct __dog {
        const SpeakerTable* vt;
        size_t b;
    };

    struct __runner_dog {
        const RunnerTable* vt1;
        size_t a;
        const SpeakerTable* vt2;
        size_t b;
    };

    __dog * createDog() {
        __dog* ptr = (__dog*)malloc(sizeof(__dog));
        ptr->vt = &__dogSpeakTable;
        ptr->b = 0;
        return ptr;
    }

    __runner_dog* createRunnerDog() {
        __runner_dog* ptr = (__runner_dog*)malloc(sizeof(__runner_dog));
        ptr->vt1 = &__dogRunnerTable; // 经过赋值之后vt1的结构体首地址等于一个具体的函数地址
        ptr->a = 0;
        ptr->vt2 = &__dogSpeakTable;
        ptr->b = 1;
        return ptr;
    }

};

int main(int _argc, char** _argv) {
    __dog* dog = createDog();
    __runner_dog* runnerDog = createRunnerDog();

    SpeakerTable** speaker = nullptr;
    {
        uint8_t* ptr = (uint8_t*)runnerDog;
        size_t offset = offsetof(struct __runner_dog, vt2);
        ptr += offset;
        speaker = (SpeakerTable**)ptr; // 等价于vt2
    }

    // (*speaker)之后就为vt2,调用结构体(SpeakerTable)中的函数 
    (*speaker)->speak(speaker);
    // 等价于
    runnerDog->vt2->speak(speaker);
    // 但不等价于
    runnerDog->vt2->speak(runnerDog); // 这是错误的
    //
    return 0;
}
五、图示:
六、代码来源:

本代码Copy自:【十分钟带你搞明白虚函数、虚表、多态的原理以及多重继承带来的问题-哔哩哔哩】 https://b23.tv/C5nszGl

七、另外的参考链接:

https://shenchunxu.blog.youkuaiyun.com/article/details/54143987

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值