每日一题(46) - 不能被继承的类

题目来自剑指Offer

题目:

使用C++设计一个不能被继承的类,

隐含要注意的问题:不能影响自己创建和销毁对象。

思路:

思路一:

思想:构造函数和析构函数为私有 + 新增俩方法

方法:把构造函数和析构函数设置为私有函数 + 新增俩方法创建对象和销毁对象

原因:

(1)把构造函数和析构函数设置为私有函数 :防止子类调用构造函数函数和析构函数,防止继承

(2)新增俩方法创建对象和销毁对象:为了不影响自己创建和销毁对象,就通过静态方法创建和销毁对象。

代码:

class SealClass
{
public:
	static SealClass* GetInstance();
	static void DelInstance(SealClass* pS);
private:
	SealClass(){}
	~SealClass(){}
};

SealClass* SealClass::GetInstance()
{
	cout<<"Create an Instance"<<endl;
	return new SealClass();
}

void SealClass::DelInstance(SealClass* pS)
{
	delete pS;
	cout<<"Del an Instance"<<endl;
}
缺点:

会影响类SealClass对象的创建,该方法只能创建堆上的对象,不能创建栈上的对象。

测试代码:

#include <iostream>
#include <assert.h>
using namespace std;

class SealClass
{
public:
	static SealClass* GetInstance(int nData);
	static void DelInstance(SealClass* pS);
private:
	SealClass(){}
	SealClass(int nData);
	~SealClass(){}
private:
	int m_nData;
};

class Drived : public SealClass
{
public:
	Drived(){}
	~Drived(){}
};

SealClass* SealClass::GetInstance(int nData)
{
	cout<<"Create an Instance"<<endl;
	return new SealClass(nData);
}

void SealClass::DelInstance(SealClass* pS)
{
	delete pS;
	cout<<"Del an Instance"<<endl;
}

SealClass::SealClass(int nData)
{
	m_nData = nData;
}

int main()
{
	/*创建自己的对象*/
	SealClass* pS = SealClass::GetInstance(1);
	SealClass::DelInstance(pS);

	//SealClass s;//错误
	
	/*创建子类*/
	//Drived d;//错误
	//Drived* pD = new Drived;//错误
	system("pause");
	return 1;
}

写程序注意几个问题:

(1)静态成员:在类中有Static修饰,在类外没有Static修饰。

(2)静态成员是属于类级别的,调用时可以直接使用类::成员调用

(2)非静态成员是不能使用类::成员的方式调用的。

思路二:

思想:使用虚基类和友元类处理。

方法:虚基类 + 虚基类构造函数和析构函数私有化 + 不能派生类SealClass变成基类友元类

(1)另外设置一个基类Base

(2)把基类Base的构造函数和析构函数设置为私有

(3)把要设置SealClass类变成基类友元类

(4)SealClass类虚拟继承Base

原因:

(1)把基类Base的构造函数和析构函数私有化:目的是为了防止让其他类从基类Base中派生,当然此时该类也不能定义对象。

(2)由于要设置SealClass类为基类Base的友元类:根据友元的性质,则该类可以自由访问基类Base中的成员,即可以该类可以不受限制的访问基类Base的构造函数和析构函数。

(3)基类的友员不能被派生类继承的:此时之后创建的Derive就不能使用父类的友元了

(4)为什么是虚继承?

主要原因:如果是虚继承的话,假设类Derive要从SealClass继承,由于是虚继承,该派生类Derive会直接调用虚基类Base的构造函数而不会通过基类SealClass,此时就会报错。

虚继承的附带优点:如果有一个类也不想被继承,且也从Base继承,且该类与SealClass具有层次关系,如果不设计为虚继承,就会出现二义性。

注意

(1)一定要设置为虚继承:如果不是虚继承的话,类Derive的对象会调用父类的构造函数,而且父类SealClass可以调用Base的构造函数和析构函数,则此时是可以有类从SealClass继承的。

(2)在有虚继承的情况下,派生类先调用虚基类的构造函数,再调用非虚基类的构造函数。虚基类的子对象在整个初始化过程中只调用一次。

缺点

有些编译器对虚基类支持不好,不易扩展。

代码:

class Base
{
public:
	friend SealClass;
private:
	Base(){}
	~Base(){}
};

class SealClass : virtual public Base
{
public:
	SealClass(){}
	~SealClass(){}
};

测试代码:

#include <iostream>
#include <assert.h>
using namespace std;

class SealClass;

class Base
{
public:
	friend SealClass;
private:
	Base(){}
	~Base(){}
};

class SealClass : virtual public Base
{
public:
	SealClass(){}
	~SealClass(){}
};


//class Drived : public SealClass
//{
//public:
//	Drived(){}
//	~Drived(){}
//};

int main()
{
	/*创建自己的对象*/
	SealClass* pS = new SealClass;
	delete pS;
	SealClass s;//错误
	
	/*创建子类*/
	//Drived d;//错误
	//Drived* pD = new Drived;//错误
	system("pause");
	return 1;
}
使用模板类:

原因:只有想让某个类不能派生对象,就可以从该类继承。

template<typename T>
class Base
{
public:
	friend T;
private:
	Base(){}
	~Base(){}
};

class SealClass : virtual public Base<SealClass>
{
public:
	SealClass(){}
	~SealClass(){}
};


你可能感兴趣的:(每日一题(46) - 不能被继承的类)