C++中定义一个不能被继承的类

1.一种错误的解法

最开始是从构造函数开始着手(先声明这种方法不能定义一个不能被继承的类,这是一种错误的方法,但是很容易往这方面想),假设存在下面的继承体系:

现在假设B是一个不能被继承的类,那么如果存在B的子类C,那么C的构造过程应该会报错,那么如何能够让B能正常构造而C不能正常构造呢?首先A,B,C的构造函数和析构函数都假设是public的,最开始想的是让B私有继承自A,根据private继承的特性,父类中public和protected的成员在子类中都会变成private的,那么A的构造函数在B中就变成private的了,然后C在继承自B时是无法访问B中的private成员的,这样C就无法调用A的构造函数了。。。。开始这样想的,但是这种想法存在一个很大的问题。就是如果是普通的函数,前面的想法是正确的,但是对于构造函数而言就不能这么思考,对于上面的继承体系。C的构造过程是这样的:

  1. 因为C直接继承自B,所以C首先需要执行B的构造函数,因为B的构造函数对C而言是public的,所以这一步不会出错;
  2. 在执行B的构造函数的时候,因为B继承自A,所以会在B构造的过程中调用A的构造函数,此时B私有继承自A,A的构造函数在B中是private的,但是B类里是可以访问到的,所以在构造B的时候也不会出错。

所以上面那种处理方法是不能让B成为不能被继承的类的,子类C仍然可以正常构造!!!

如果把上面B私有继承替换成虚拟的私有继承呢?

此时看看构造C的过程:

  1. 在这个继承体系中存在了虚基类,所以首先应该调用A的构造函数,因为是跳过了B直接调用A,所以此时A的构造函数是public,这一步不会出错;
  2. 然后C调用B的构造函数,能正常调用

从上面的分析可以看出使不使用虚基类效果是一样的。

#include <iostream>
#include <string>

using namespace std;

class A
{
	public:
			int a;
			A()
			{
				cout<<"a"<<endl;
			}
};

//这里使不使用虚基类效果是一样的
class B:private  virtual A
{

};

class C:public B
{

};

int main()
{
	A a;
	B b;
	C c;
	cout<<"success"<<endl;
	return 0;
}

2.使用静态函数来实现

上面的方法虽然是错误的,但是它也提供了一种思路,只是有些地方没有处理好。定义不能被继承的累关键仍然是要从构造函数着手。

在C++中要定义一个不能被继承的类,可以这么思考,如果存在子类,那么子类会调用父类的构造函数,那么我们可以将这个类的构造函数和析构函数都声明是私有的,那么这样它的子类构造时就会报错,这样这个类就是不能被继承的了。如果我们要获取这个类的对象,可以通过一个静态的方法来获取,这个静态 方法可以获取这个类的对象,也可以获取这个类的对象的指针,对应于在栈上还是在堆上分配内存。

2.1堆中的实现

先看在堆上分配内存的情况:

#include <iostream>

using namespace std;

class A
{
	//构造函数和7构函数都被声明是私有的,这样就不能被继承了
	private:
	A()
	{
		cout<<"a con"<<endl;
	}
	~A()
	{
		cout<<"a des"<<endl;
	}

	//提供两个公有的方法来获取和释放A类型的对象
	public:
	static A* getA()
	{
		A *a=new A();
		return a;
	}
	static void deleteA(A* a)
	{
		delete a;
	}
};

class B:public A
{

};

int main()
{
	A* a=A::getA();
	A::deleteA(a);
//	B b;
	return 0;
}

上面的代码能正常运行:但是注意这种方法构造的A对象都位于堆内存中,并且一定要注意通过定义的A::getA()来获取对象,A::delete(a)来释放对象,不能通过delete a来释放对象,因为此时析构函数是私有的了。

可以发现A的构造函数和析构函数都正常执行了,如果把main函数中注释的哪行代码注释掉,结果就会报错:一直提示A的构造函数是私有的。

2.2栈中的实现

上面这种方式已经可以定义一个不能被继承的类,但是对象A始终存在堆内存中,于是我想能不能尝试在栈内存中构造A的对象?

在栈上构造对象理论上讲是只需要在静态函数getA中返回一个对象A就可以了,不需要返回一个指向A的指针,如下。但是这里构造A是没问题了,可是析构A时出问题了,因为在getA返回对象a时存在一个临时对象,这个临时对象需要析构,然后main函数结束时也有一个对象需要析构,所以析构时会提示错误。

#include <iostream>

using namespace std;

class A
{
		private:
				A()
				{
					cout<<"a con"<<endl;
				}
		//public:
				~A()
				{
					cout<<"a desc"<<endl;
				}
		//提供两个公有的方法来获取和释放A类型的对象
		public:
		static A getA()
		{
			A a;
			return a;
		}
};

class B:public A
{

};

int main()
{
	A a=A::getA();
	B b;
	return 0;
}

出错提示:

这个错误提示和上面的分析是一样的,即在调用A的析构函数时出错,如果把上面的析构函数声明是public(即把上面的析构函数上面的对public的注释去掉),构造函数声明是private的,那么就能正常构造A对象了。并且不能定义A的子类了。但是强烈不建议这么这种做法,因为一般构造函数和析构函数的访问修饰符是一样的!!!!

3.使用友元和模板

上面的解法总有一种怪怪的感觉,其实在第一错误的解法上稍微做一点改进就有一种很漂亮的解法了。

仍然是上面那个继承体系:

  1. 将A的构造函数和析构函数都声明为private的,但是将B作为A的友元类,这样B就可以访问A的构造函数和析构函数了,此时B能正常构造;
  2. 为了使B的子类C不能被正常构造,可以让C直接调用A的构造函数,那么将B设置成虚拟继承自A;
  3. 因为友元关系是不能被继承的,所以C调用A的构造函数时会报错

和第一种错误的解法相比,主要使将A的构造函数和析构函数声明是private的了,并且将B声明是A的友元类,其实这种解法和A的思路是一样的,就是让B能调用A的构造函数,让B的子类不能调用A的构造函数,只是第一种错误的解法没有满足这个要求。

更进一步,可以将它写成模板:

#include <iostream>

using namespace std;

template<class T>
class A
{
		friend T;//注意这里不需要class关键字
		//将构造函数和7构函数都声明是私有的
		private :
		A()
		{
		}
		~A()
		{

		}

};

class B:public virtual  A<B> //这里一定需要使用虚继承,只有使用虚继承,它的子类才会直接调用A类的构造函数,这样才会报错,如果是普通继承,那么通过B类调用A类的构造函数时时不会报错的
{

};

class C:public B
{

};

int main()
{
	B b;
	cout<<"success"<<endl;
//	C c;
	return 0;

}

这就是最终的一种很好的写法了。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-07 11:31:33

C++中定义一个不能被继承的类的相关文章

如何定义一个不能被继承的类

class VString{//默认的存取控制方式就是私有     VString();     VString(char*);     VString(string);     friend class String; }; class String:virtual VString{ public:     String(){         //写你的代码     }     String(char*){         //写你的代码     }     String(string){  

C++之如何实现一个不能被继承的类

C++中如何实现一个不能被继承的类? 在C#中可以使用sealed,Java中可以使用final来表示一个类不能被继承,而在c++中并没有这个,那我们怎么在c++中实现一个不能被继承的类呢? 1.把构造函数设为私有 这是最简单的一种办法了,那就是把构造函数设为私有,因为我们都知道当一个类试图从它那里继承的时候,必定会因为调用基类的构造函数,而基类的构造函数是私有的,这样会导致编译错误: 可是这样我们又怎么获得这个类的实例呢?我们可以定义公有的静态函数来获取和释放,有点类似单例模式~ class

C++设计实现一个不能被继承的类

C++不同于Java,Java中被final关键字修饰的类不能被继承,C++能实现不被继承的类,但是需要自己实现. 为了使类不被继承,最好的办法是使子类不能构造父类的部分,此时子类就无法实例化整个子类.在C++中,子类的构造函数会自动调用父类的构造函数,子类的析构函数也会自动的调用父类的析构函数,所以只要把类的构造函数和析构函数都定义为private()函数,那么当一个类试图从他那儿继承时,必然会由于试图调用构造函数.析构函数而导致编译错误.此时该类即不能被继承. 但由此会造成一个问题,priv

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

题目:用c++实现一个不能被继承的类 题解分析: 常规解法: 首先想到的是在C++ 中,子类的构造函数会自动调用父类的构造函数.同样,子类的析构函数也会自动调用父类的析构函数. 要想一个类不能被继承,我们只要把它的构造函数和析构函数都定义为私有函数. 那么当一个类试图从它那继承的时候,必然会由于试图调用构造函数.析构函数而导致编译错误. 可是这个类的构造函数和析构函数都是私有函数了,我们怎样才能得到该类的实例呢? 这难不倒我们,我们可以通过定义静态函数来创建和释放类的实例.基于这个思路,我们可以

用C++设计一个不能被继承的类(转)

在Java 中定义了关键字final,被final修饰的类不能被继承. 首先想到的是在C++中,子类的构造函数会自动调用父类的构造函数.同样,子类的析构函数也会自动调用父类的析构函数.要想一个类不能被继承,只要把它的构造函数和析构函数都定义为私有函数.那么当一个类试图从它那继承的时候,必然会由于试图调用构造函数.析构函数而导致编译错误. 可是这个类的构造函数和析构函数都是私有函数了,怎样才能得到该类的实例呢?可以通过定义静态来创建和释放类的实例.基于这个思路,可以写出如下的代码: 1 /////

c++设计一个不能被继承的类,原因分析

用C++实现一个不能被继承的类(例1) #include <iostream> using namespace std; template <typename T> class Base{     friend T; private:     Base(){         cout << "base" << endl;     }     ~Base(){} }; class B:virtual public Base<B>

c++设计一个不能被继承的类

摘要:使用友元.私有构造函数.虚继承等方式可以使一个类不能被继承,可是为什么必须是虚继承?背后的原理又是什么? 用C++实现一个不能被继承的类(例1) 1 #include <iostream> 2 using namespace std; 3 4 template <typename T> 5 class Base{ 6 friend T; 7 private: 8 Base(){ 9 cout << "base" << endl; 1

用C++实现一个不能被继承的类

一道笔试题的思考: 记得,找工作时,遇到了这样的一道笔试题.记不清是那个公司的笔试题,反正觉得自己当时还真费了一点功夫的,但是也就搞定了一部分,结果还是被另一部分给鄙视啦! 现在静下来分析实现如下: 题目:用C++设计一个不能被继承的类 不能被继承?不能被继承?不能被继承?按照继承的理论知识分析,我们只要把类的构造函数设置为私有的,即可解决问题. 因为那样的话,子类就没有办法访问基类的构造函数,从而就阻止了进行子类构造对象的任务实现,也就达到了不可继承的目的. 但是,假设那样,这个类我们在其它地

如何产生一个不能被继承的类

对于这个问题,我首先想到的是将“父类”的构造函数声明为私有的,这样的话,子类就不能在自己的构造函数中调用父类的构造函数(就算没有显示调用父类的构造函数,编译器也会自动在子类的构造函数中插入调用父类构造函数的代码),于是就实现了不能被继承的类.同时,我们还是要能够产生这个类的对象,所有要公开一个方法,在该方法中调用私有构造函数.这种解法有点像Singleton. class CNoChildren{ public: CNoChildren* createCNoChildren(){ CNoChil