【C++】如何防止一个类被继承 && C语言如何实现继承与多态

如何防止一个类被继承

在C#中定义了关键字sealed,被sealed修饰的类是不能被继承的。同样在Java中也有关键字final表示一个类型不能被继承。然而在C++中却没有类似于sealed的关键字,C++11提供final关键字防止继承,因此就只能模拟实现它。这道题出自剑指offer,备受青睐的一道面试题。

  • 防止被继承的思想

在C++中,子类的构造函数会自动调用父类的构造函数,子类的析构函数也会自动调用父类的析构函数。说到这你可能明白了,要想一个类不能被继承,我们只要把它的构造函数和析构函数都定义为私有函数,那么当一个类试图去继承的时候,必然会由于调用构造函数和析构函数而导致编译错误。

下面就为大家介绍两种方法来防止一个类被继承。

将构造函数设为私有函数

我们将构造函数和析构函数定义为私有函数,那么我们如何才能得到该类型的实例呢?我们可以通过定义公有的静态函数来创建和释放类的实例

#include <iostream>
using namespace std;
class SealedClass
{
public:
	static SealedClass* GetInstance()
	{
		return new SealedClass();
	}
	static void DeleteInstance(SealedClass* _Instance)
	{
		delete _Instance;
	}
private:
	SealedClass()
	{}
	~SealedClass()
	{}
};
class Derive :public SealedClass
{
public:
	Derive()
	{}
	~Derive()
	{}
};
int main()
{
	system("pause");
	return 0;
}

在这里插入图片描述

发现连编译都通过不了,说明 ·这个类是不能被继承的,但是这样的类让人总感觉使用起来不方便,比如我们只能得到位于堆上的实例,而得不到栈上的实例。

使用虚拟继承

使用虚拟继承就会弥补上述的缺点,我们可以在堆上或栈上创建实例,当然我们不仅将派生类声明为基类的友元,而且还引入了虚拟继承的特性,具体我们先看代码:

#include <iostream>
using namespace std;
template<class T>
class MakeSealed
{
	friend class SealedClass;
private:
	MakeSealed()
	{}
	~MakeSealed()
	{}
};
class SealedClass :virtual public MakeSealed<SealedClass>
{
public:
	SealedClass()
	{}
	~SealedClass()
	{}
};
int main()
{
	system("pause");
	return 0;
}

在这里插入图片描述
现在编译运行肯定也不会出错了。尽管MakeSealed的构造函数与习惯函数都是私有的,但由于类SealedClass是它的友元类型,因此在SealedClass中调用MakeSealed的构造函数和析构函数就不会出错。

但是如果我们从派生类中继承一个类并创建它的实例时,却不能编译通过,比如我们在派生类SealedClass中继承出类型Code:

class Code :public SealedClass
{
public:
	Code()
	{}
	~Code()
	{}
};

在这里插入图片描述
因为SealedClass是从类MakeSealed中虚拟继承的,在调用Code的构造函数时,会跳过SealedClass而直接调用MakeSealed的构造函数,但是Code不是类MakeSealed的友元函数,也就意味着不能访问人家的私有函数。

现在我们将虚拟继承的代码在linux的G++环境下跑一下看会发生什么:

在这里插入图片描述

g++环境下错误还是很多的,说明该程序的可移植性并不好,这是因为gcc和g++编译器中还不支持模板参数类型作为友元函数。

C语言如何实现继承与多态

实现要求如下:
C 实现一个 struct A 和 stuct B 包含一个 int 成员 a 和 b,要求达到B 继承 A 的效果,也就是 B里面包含一个 A,并且能达到多态的效果,也就是一个 A* p 指向一个指向A 调的是 A 的函数,指向 B 调的是 B 的函数
具体效果如下C++演示:

#include <iostream>
using namespace std;

class A
{
public:
    virtual void fun()
    {
        printf("A::fun()\n");
    }
    int _a;
};

class B:public A
{
public:
    virtual void fun()
    {
        printf("B::fun()\n");
    }
    int _b;
};

int main()
{
    A a;
    B b;
    A* p = &a;
    p->fun();
    p = &b;
    p->fun();

    return 0;
}
 

在这里插入图片描述

  • 参考代码
#include <stdio.h>

typedef void(*FUN) ();//定义函数指针

struct A
{
    FUN _f;//C语言的结构体不支持成员函数,只能用函数指针来实现“含有成员函数”
    int _a;
};

struct B
{
    struct A a;//C语言不支持继承,只能用嵌套结构体实现“B继承A”
    int _b;
};

void funA()
{
    printf("A::fun\n");
}
void funB()
{
    printf("B::fun\n");
}

int main()
{
    struct A a;
    struct B b;
    a._f = funA;
    b.a._f = funB;
    struct A* p = &a;
    p->_f();
    p = (struct A*)&b;
    p->_f();

    return 0;
}
 

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农印象

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值