首页 > 编程语言 >C++设计一个类:不能被继承

C++设计一个类:不能被继承

时间:2022-11-04 11:08:52浏览次数:45  
标签:友元 Base cout 继承 C++ num 设计 finalClass


C++如何设计一个不能被继承的类?

我们首先想到,不能被继承,那把构造函数和析构函数设计成私有的不就行了,这样的话子类不能访问父类的构造函数和析构函数,也就无法继承了。

然而这样一来,这个类在其他地方也就不能实例化了,没有存在的意义了。

这时候我们应该想到静态方法,我们可以通过静态方法来返回类的实例,然后通过另一个静态方法来释放该类对象。

看如下代码:

class A
{
public:
static A* getInstance(int n)
{
A* pa = new A();
pa->num = n;
return pa;
}
static void destructInstance(A* pInstance)
{
delete pInstance;
pInstance = NULL;
}
private:
A(){cout << "construct A" << endl;}
~A(){cout << "destruct A" << endl;}
public:
int num;
};

那么?为什么必须返回指针而不返回对象的引用呢?
看下面代码:

class B
{
public:
static B& getInstance(int n)
{
B pb;
pb.num = n;
return pb;
}

static void destructInstance(B& pInstance)
{
pInstance.~B();
}

private:
B()
{
cout << "construct B" << endl;
}
~B()
{
cout << "destruct B" << endl;
}
public:
int num;
};

上面的代码是返回引用,我们做一个测试:

void test()
{
cout << " return pointer " << endl;
A *sa = A::getInstance(9);
cout << "num is:" << sa->num << endl;
A::destructInstance(sa);

cout << " return reference " << endl;
B &sb = B::getInstance(9);
cout << "num is:" << sb.num << endl;
B::destructInstance(sb);
}

观察结果:

C++设计一个类:不能被继承_静态方法


可以看出:

当返回引用时,在输出num之前,对象就已经被析构了。

这是因为在static B& getInstance()函数中声明的对象B pb是局部变量,当函数运行完,该变量就会被释放掉,而返回的却是已经被释放掉的对象的引用,这无疑会造成内存泄漏。

所以,只能通过new来动态申请堆上的内存,然后返回指针,而不能返回引用。

如果这样的话,类A虽然不能被继承,但却只能在堆上创建对象,而不能在栈上创建对象。
若我们只想创建一个临时对象,使用栈空间会更高效方便一些。

如何能使我们的类既不能被继承,又能够在堆和栈上都可以创建对象呢?

我们考虑到友元,友元可以访问类的私有成员。

因此,我们可以创建一个基类,使其构造函数和析构函数为私有成员,然后让我们设计的非继承类成为基类的友元。

看下面的代码:

template <typename T>
class Base
{
friend T; // 这种写法好像是C++11才支持的
private:
Base()
{
cout << "construct Base" << endl;
}
~Base()
{
cout << "destruct Base" << endl;
}
};

class finalClass: virtual public Base<finalClass>
{
public:
finalClass():num(0)
{
cout << "construct finalClass" << endl;
}
finalClass(int n):num(n)
{
cout << "construct finalClass" << endl;
}
~finalClass()
{
cout << "destruct finalClass" << endl;
}
int num;
};

看测试代码:

void testFriend()
{
cout << "--------------object on heap-----------------" << endl;
finalClass *pfc = new finalClass(9); // 堆上的对象
cout << "num is: " << pfc->num << endl;
delete pfc;
cout << "-------------Object on stack-----------------" << endl;
finalClass fc(9); // 栈上的对象
cout << "num is: " << fc.num << endl;
}

观察结果:

C++设计一个类:不能被继承_构造函数_02

无论在堆上创建对象,还是在栈上创建对象都可以。
这里需要说明的是,finalClass对Base的继承必须是虚继承,这样一来当derivedClass继承finalClass时就会去直接调用Base的构造函数,但由于Base的构造函数是私有的,而derivedClass不是Base的友元,因此会报出编译错误。

于是,我们设计的类finalClass就是一个完整的不能被继承的类。

另外需要说明的是,友元关系不具有传递性。finalClass是Base的友元,即使derivedClass继承了finalClass, derivedClass也不是Base的友元。
即:友元关系不能继承,基类的友元对派生类的成员没有访问权限,如果基类被授予友元关系,则只有基类具有特殊访问权限,该基类的派生类不能访问授予友元关系的类。

现在,C++11中已经像java一样有了final关键字,被final关键字修饰的虚函数(只能是虚函数)不能被重载,被final修饰的类不能被继承。


标签:友元,Base,cout,继承,C++,num,设计,finalClass
From: https://blog.51cto.com/u_15861560/5822285

相关文章

  • C++——单调队列
    classSolution{public:classMyqueue//单调队列{public:deque<int>que;//因为只维护了队列最大值,故在pop时判断滑动窗口最......
  • 数据库设计心得——by你说的都队
     项目介绍我们的项目是基于跨层优化的视频传输系统,在dash架构的基础上实现视频的流畅播放,构建一个供用户交流的视频分享平台。设计思路我们小组根据前期的需求文档和......
  • 初识设计模式 - 备忘录模式
    简介备忘录设计模式(MementoDesignPattern)也叫作快照(Snapshot)模式,主要用于实现防丢失、撤销、恢复等功能。其定义是,在不违背封装原则的前提下,捕获一个对象的内部状态,并......
  • 数据库设计心得-4班-软小五比奇堡乐园队
    小组名软小五比奇堡乐园项目名软件工程导论实践教学管理平台小组成员张凯航(PM)、李林畅、李佳豪、牟洺楷、张恩硕数据库简介数据库(DataBase,DB):指长期保存在计算机的存......
  • 继承
    概念:extends  子类继承父类  class子类extends父类子类拥有父类非private的属性、方法。子类可以拥有自己的属性和方法。Java的继承是单继承,但是可......
  • C++ 获取时间戳
    获取unix时间戳std::time_tresult=std::time(nullptr);或者:constautop1=std::chrono::system_clock::now();std::cout<<"secondssinceepoch:......
  • 数据结构(一):(顺序表)设计算法删除所有数字字符
    好家伙,写作业 什么是顺序表:顺序表是在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素、使得线性......
  • 设计模式:责任链模式的应用场景及源码应用
    一、概述责任链模式(ChainofResponsibilityPattern)是将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首......
  • c++11 unique_ptr
    unique_ptr使用详解      ......
  • C++静态成员和静态函数的正例和反例
      上图所示的代码都是正确的、并且能够按正常人的预期执行。首先提示一点、C++要用类名调用静态函数或者引用变量时、不是像Java一样用点号、而是用两个冒号! 错误......