C++-怎样使类不能被继承

发布于 2016-11-11 17:50:20 字数 20 浏览 1876 评论 7

如何使一个类能够禁止被继承

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

浮生未歇 2017-06-16 19:59:28

首先,C++ 从语言层面并不能禁止类被继承,但有的编程语言(诸如 C# 提供了 sealed class、Java 提供了 final class)则存在语言层面的禁止机制。

所以,如果当你设计一个类的时候,不希望他被继承,有几个辅助方案:

(1)
让他变成一个内部类(inner class),在《Effective C++》的条款 39 中提到一个例子:

 class Widget{
private:
class WidgetTimer: public Timer{
public:
virtual void onTick() const;
};
WidgetTimer timer;
};

这样该 WidgetTimer 就只是一个为其内部服务的类。

(2)
让构造函数为私有(private constructor),但是继承还是可以的,只是基类无法被初始化,因此试图继承该类的类都会报错。

偏爱自由 2017-05-13 09:57:31

加上 final 修饰符
final class Test

归属感 2017-03-31 01:33:59

主要的思路就是使子类不能构造父类的部分,这样子类就没有办法实例化整个子类.这样就限制了子类的 继承. 所以我们可以将父类的构造函数声明成为私有的,但是这样父类不就不能实例化.我想可以添加一个静态帮助函数来进行构造. 虽然这样很简陋.但是这的确是一种解决方法.

虐人心 2017-03-26 18:28:04

Q: 我能防止别人从我的类继承吗?

A: 可以的,但何必呢?好吧,也许有两个理由:

出于效率考虑——不希望我的函数调用是虚的
出于安全考虑——确保我的类不被用作基类(这样我拷贝对象时就不用担心对象被切割(slicing)了)[译注:“对象切割”指,将派生类对象赋给基类变量时,根据C++的类型转换机制,只有包括在派生类中的基类部分被拷贝,其余部分被“切割”掉了。]

根据我的经验,“效率考虑”常常纯属多余。在C++中,虚函数调用如此之快,和普通函数调用并没有太多的区别。请注意,只有通过指针或者引用调用时才会启用虚拟机制;如果你指名道姓地调用一个对象,C++编译器会自动优化,去除任何的额外开销。

如果为了和“虚函数调用”说byebye,那么确实有给类继承体系“封顶”的需要。在设计前,不访先问问自己,这些函数为何要被设计成虚的。我确实见过这样的例子:性能要求苛刻的函数被设计成虚的,仅仅因为“我们习惯这样做”!

好了,无论如何,说了那么多,毕竟你只是想知道,为了某种合理的理由,你能不能防止别人继承你的类。答案是可以的。可惜,这里给出的解决之道不够干净利落。你不得不在在你的“封顶类”中虚拟继承一个无法构造的辅助基类。还是让例子来告诉我们一切吧:

class Usable;

class Usable_lock {
friend class Usable;
private:
Usable_lock() {}
Usable_lock(const Usable_lock&) {}
};

class Usable : public virtual Usable_lock {
// ...
public:
Usable();
Usable(char*);
// ...
};

Usable a;

class DD : public Usable { };

DD dd; // error: DD::DD() cannot access
// Usable_lock::Usable_lock(): private member

(参见《The Design and Evolution of C++》,11.4.3节)
以上内容引用至:http://www.stroustrup.com/bstechfaq.htm

灵芸 2017-01-15 13:21:31

Effective C++ 的原话是构造函数声明为私有并不予实现。。。。

虐人心 2017-01-04 18:17:00

很简单 的,
继承的时候子类在构造的时候要先执行父类的构造函数,所以只要让类的构造和析构函数都置成private,编译器就会告诉我们这个类不能被继承了。
这就会引起另一个问题,这个类怎么实例化?
  实例化有两种方法
  1、用static的函数返回实例化的对象指针
  2、用friend的全局函数返回实例化的指针,这个方法就是有点不面向对象

夜无邪 2016-12-03 07:56:33

能够想到,类的构造函数和析构函数是关键。因为子类的构造函数会自动调用父类的构造函数。子类的析构函数也会自动调用父类的析构函数。所以要想使一个类不能被继承,只有把它的构造函数和析构函数都定义为私有函数或保护函数,那么当一个类试图从这个类继承的时候,必然会先调用构造函数而产生编译错误,从而导致继承失败。
这个不能被继承类的构造函数和析构函数都是私有函数,那么怎样才能得到该类的实例呢? 这倒不难,可以通过定义公有的静态函数来创建和释放类的实例,实现该类不能被继承但能被实例化的功能。
基于这个思路,我们可以写出如下代码:

#include<iostream>
using namespace std;

class SealedClass
{
private: // 私有成员
SealedClass() { }; // 构造函数
~SealedClass() { }; // 析构函数
public:
int m_number;
static SealedClass* GetInstance(int number) // 用于构造的函数
{
SealedClass * pInstance = new SealedClass();
pInstance->m_number = number;
return pInstance;
}
static void DeleteInstance(SealedClass* pInstance) // 用于析构的函数
{
delete pInstance;
pInstance = 0;
}
};

int main(void)
{
SealedClass * p = SealedClass::GetInstance(9);
cout<<"m_number is : "<<p->m_number<<endl;
SealedClass::DeleteInstance(p);
cout<<"m_number is : "<<p->m_number<<endl;

return 0;
}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文