一、不能被继承的要求
- 构造函数设置为私有
因为创建子类时需要访问父类的构造函数 析构函数设置为私有
因为销毁子类时需要访问父类的析构函数所以一个类不能被继承需要将析构函数和构造函数设置为私有的。
但是两个函数被设置为私有后,这样一来这个类在其他地方不能实例化,没有存在的意义。
二、解决不能继承的类不能实例化的问题
1、通过静态方法来解决
这时候你是不是想到了静态方法,是啊,我们可以通过静态方法来返回类的实例,然后通过另一个静态方法来释放该类对象。代码如下:
静态成员函数不属于类对象所有(属于类的一部分)可以创建一个类来调用静态成员函数
也可直接不创建一个类,Base::来调用静态成员函数,因为他的生命周期是全局存在的,
class Base
{
public:
static Base* getInstance(int n)
{
Base* pa;//这一步跳过
pa = new Base(); //执行到这一步会执行一个构造函数来构造一个Base
pa->_num = n;
return pa;
}
static void destructInstance(Base* pInstance)
{
delete pInstance; //在这里会调用析构函数
pInstance = NULL;
}
private:
Base()
{
cout<<"Base::Base"<<endl;
}
~Base()
{
cout<<"Base::~Base"<<endl;
}
public:
int _num;
};
int main()
{
Base* pInstance = Base::getInstance(10);
cout<<pInstance->_num<<endl;
Base::destructInstance(pInstance);
return 0;
}
你可能会问,为什么必须返回指针而不返回对象的引用呢?这里必须返回指针,而不能像如下代码一样返回引用:
class Base
{
public:
static Base& getInstance(int n)
{
Base par;
par.num = n;
return par;
}
static void destructInstance(Base& pInstance)
{
pInstance.~Base();
}
private:
Base(){cout << "construct Base" << endl;}
~Base()
{
cout << "destruct Base" << endl;
}
public:
int num;
};
当返回引用时,在输出num之前,对象就已经被析构了。因为在static Base& getInstance()函数中声明的对象Basepar是局部变量,当函数运行完,该变量就会被释放掉,而返回的却是已经被释放掉的对象的引用,这无疑会造成内存泄漏。所以,只能通过new来动态申请堆上的内存,然后返回指针,而不能返回引用。
可是这样一来,类A虽然不能被继承,但却只能在堆上创建对象,而不能在栈上创建对象。要知道很多时候,我们只想创建一个临时对象,使用栈空间会更高效方便一些。
也不能返回一个类,因为在其他函数需要创建一个类来接受这个类,又回到了最初的问题(因为在其他函数不能对该类进行实例化)
static Base getInstance(int n)
{
Base par;
par.num = n;
return par;
}
如何才能使我们的类既不能被继承,又能够在堆和栈上都可以创建对象呢?
2、使用友源(堆和栈上都可以创建对象)
友源函数可以访问类的私有成员
class Base
{
public:
friend void test();
private:
Base(int x)
:_num(x)
{
cout<<"Base::Base"<<endl;
}
~Base()
{
cout<<"Base::~Base"<<endl;
}
public:
int _num;
};
class Derived:public Base
{
public:
int _a;
};
void test()
{
cout << "--------------object on heap-----------------" << endl;
Base *pfc = new Base(9); // 堆上的对象
cout << "num is: " << pfc->_num << endl;
delete pfc;
cout << "-------------Object on stack-----------------" << endl;
Base fc(10); // 栈上的对象
cout << "num is: " << fc._num << endl;
//Derived d;//这样仍然不可以,因为创建派生类仍然需要调用基类的构造函数
}
int main()
{
test();
return 0;
}