剑指offer (48) c++实现一个不能被继承的类

题目:用c++实现一个不能被继承的类

题解分析:

常规解法:

首先想到的是在C++ 中,子类的构造函数会自动调用父类的构造函数。同样,子类的析构函数也会自动调用父类的析构函数。

要想一个类不能被继承,我们只要把它的构造函数和析构函数都定义为私有函数。

那么当一个类试图从它那继承的时候,必然会由于试图调用构造函数、析构函数而导致编译错误。

可是这个类的构造函数和析构函数都是私有函数了,我们怎样才能得到该类的实例呢?

这难不倒我们,我们可以通过定义静态函数来创建和释放类的实例。基于这个思路,我们可以写出如下的代码:

class FinalClass {
    public:
        static FinalClass* GetInstance() {
            return new FinalClass();
        }

        static void DelInstance(FinalClass* pInstance) {
            delete pInstance;
            pInstance = NULL;
        }

    private:
        FinalClass() { }
        ~FinalClass() { }
};

这个类是不能被继承,但是有如下缺点:

1. 需要一个static public member function来创建一个实例

2. 类如果有多个构造函数,所有的构造函数都需要有一个相应的 static-public-member function

3. 类实例对象只能创建在堆上,不能在栈上

新奇解法:

class Final; // Forward declaration
class FinalLocker {
    public:
        friend class Final;
    private:
        FinalLocker();
        ~FinalLocker();
};

class Final : public virtual FinalLocker {
    public:
        Final();
        ~Final();
};
Final objFinal;    //OK - no problem
Derived objDer;   // Error! - Cant access FinalLocker‘s c‘tor

FinalLocker类将其所有ctor和dtor设为private

Final被设为为FinalLocker的friend,这样Final就可以访问 FinalLocker的所有member function,包括private的

Final虚继承FinalLocker,而FinalLocker的ctor和dtor都是private的,我们仍然可以创建Final的实例,堆上栈上都可以,因为Final是FinalLocker的friend

当Derived试图继承Final时,Derived的构造函数必须调用 FinalLocker的构造函数,而FinalLocker的构造函数是private的,所有编译器出错

这是因为 Derived不是FinalLocker的friend,记住 friend关系不是顺沿继承的,Final是 FinalLcker的friend,Derived不一定是,除非显式声明

相关资料:

http://prashanth-cpp.blogspot.com/2007/01/implementing-final-class-in-c.html

http://www.stroustrup.com/bs_faq2.html#no-derivation

扩展:c++11新添了 final 和 override关键字

final关键字有两个作用:

1. 禁止一个类被继承

class Base final {
    ...
};

class Derived : public Base {    // error,不能从final类继承
    ...
};

2. 禁止虚函数被重定义,仅限于虚函数

class Base  {
    virtual void func() final;
};

class Derived : public Base {
    virtual void func();    // error,不能重定义基类的final虚函数
};

剑指offer (48) c++实现一个不能被继承的类

时间: 2024-08-15 10:18:56

剑指offer (48) c++实现一个不能被继承的类的相关文章

剑指offer 二叉树的下一个结点

题目描述 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针. 思路: 1)如果一个节点有右子树,那么它的下一个结点就是它的右子树中的最左子节点: 2)如果一个节点没有右子树,并且它还是它父节点的右子节点,我们可以沿着指向父节点的指针一直向上遍历,知道找到一个是它父节点的右子节点的左子节点的节点,就是第一个向右转的子部分根节点. /* struct TreeLinkNode { int val; struct Tr

[剑指Offer] 48.不用加减乘除做加法

题目描述 写一个函数,求两个整数之和,要求在函数体内不得使用+.-.*./四则运算符号. [思路] 首先看十进制是如何做的: 5+7=12,三步走第一步:相加各位的值,不算进位,得到2.第二步:计算进位值,得到10. 如果这一步的进位值为0,那么第一步得到的值就是最终结果.第三步:重复上述两步,只是相加的值变成上述两步的得到的结果2和10,得到12. 同样我们可以用三步走的方式计算二进制值相加: 5-101,7-111 第一步:相加各位的值,不算进位,得到010,二进制每位相加就相当于各位做异或

剑指Offer——二叉树的下一个结点

题目描述: 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针. 分析: 如果该结点存在右子树,那么返回右子树的最左结点. 如果该结点不存在右子树,那么如果该结点不是其父结点的最右结点,那么返回父结点:否则一直找到最大子树的最右结点是该结点,那么返回该最大子树的根结点的父结点. 代码: 1 /* 2 struct TreeLinkNode { 3 int val; 4 struct TreeLinkNode *le

剑指Offer——二叉树的下一个节点

1.题目描述 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针. 2.代码实现 /* public class TreeLinkNode { int val; TreeLinkNode left = null; TreeLinkNode right = null; TreeLinkNode next = null; 指向父节点 TreeLinkNode(int val) { this.val = val; } }

剑指offer——48把数字翻译成字符串

题目要求: 给定一个数字,按照如下规则翻译成字符串:0翻译成“a”,1翻译成“b”...25翻译成“z”.一个数字有多种翻译可能,例如12258一共有5种,分别是bccfi,bwfi,bczi,mcfi,mzi.实现一个函数,用来计算一个数字有多少种不同的翻译方法. 解题思路: 下面我们从自上而下和自下而上两种角度分析这道题目,以12258为例: 自上而下,从最大的问题开始,递归 : 有很多子问题被多次计算,比如258被翻译成几种这个子问题就被计算了两次. 自然想到可以用动态规划来解决,用f(i

剑指offer编程题Java实现——面试题7相关题用两个队列实现一个栈

剑指offer面试题7相关题目:用两个队列实现一个栈 解题思路:根据栈的先入后出和队列的先入先出的特点1.在push的时候,把元素向非空的队列内添加2.在pop的时候,把不为空的队列中的size()-1份元素poll出来,添加到另为一个为空的队列中,再把队列中最后的元素poll出来两个队列在栈不为空的情况下始终是有一个为空,另一个不为空的.push添加元素到非空的队列中,pop把非空队列的元素转移到另一个空的队列中,直到剩下最后一个元素,这个元素就是要出栈的元素(最后添加到队列中的元素). 1

170319 剑指offer 1.把一个字符串转化成整数(简单问题的全面性考虑)

工作的时间越长,越感觉基础的重要性,当我们对程序的框架结构越来越熟悉的时候,越会注意这一点,在工作当中,功能的实现是重要的,但是代码的健壮性,重用性,与扩展性确往往更为重要,在学习新技术的同时,我们或许应该抽出一点时间,去思考代码可能出现的问题. 关于剑指offer的这本书,可能所有刚毕业找工作的人,或者准备找工作的人都曾经看过,但是当时我们面对一些东西的时候心情过于浮躁,往往忽视了简单的却又十分重要的环节,(ps:也可能只有我是这样) 面试中一道简单的问题(把一个字符串转化成整数) 可能接触c

《剑指Offer》附加题_用两个队列实现一个栈_C++版

在<剑指Offer>中,在栈和队列习题中,作者留下来一道题目供读者自己实现,即"用两个队列实现一个栈". 在计算机数据结构中,栈的特点是后进先出,即最后被压入(push)栈的元素会第一个被弹出(pop);队列的特点是先进先出,即第一个进入队列的元素将会被第一个弹出来.虽然栈和队列特点是针锋相对,但是两者却相互联系,可以互相转换. 在"用两个队列实现一个栈"问题中,我们用两个队列的压入和弹出来模拟栈的压入和弹出.我们通过画图的手段把抽象的问题形象化. 在上

【剑指offer】删除在另一个字符串中出现的字符

转载请注明出处:http://blog.csdn.net/ns_code/article/details/27110873 剑指offer上的字符串相关题目. 题目:输入两个字符串,从第一字符串中删除第二个字符串中所有的字符.例如,输入"They are students."和"aeiou",则删除之后的第一个字符串变成"Thy r stdnts.". 这里主要要分析两个方面: 1.如何判断那些字符是需要删除的字符.同很多字符串问题一样,可以开辟