1 限制对象只能在堆上生成
贴代码:
#include<iostream>
using namespace std;
class Demo
{
public:
Demo(int x)
{
this -> x = x;
}
//外部不能访问析构函数,因此需要在内部打开一个缺口,访问析构函数
//delete是先执行析构函数,然后释放内存
void destroy()
{
delete this;
}
void get()
{
cout << x << endl;
}
void set(int x)
{
this->x = x;
}
protected:
~Demo() {};//可以被继承,但是限制外部调用该析构函数在栈上生成对象
private:
int x;
};
int main()
{
//Demo d(2);//报错,不能在栈上定义对象
Demo *pDemo = new Demo(2);
pDemo->print();
pDemo->destroy();
pDemo = nullptr;//必须将指针置空,否则下面两句会正常执行
pDemo->set(5);//运行时报错
pDemo->get();
system("pause");
return 0;
}
2 只能堆上生成的对象被包含与被继承
2.1 被包含
不能直接包含Demo对象:
class ContainerDemo
{
private:
Demo demo(0);//报错
...
};
可以修改为包含Demo的指针,并在构造函数内初始化,即可。
class ContainerDemo
{
private:
Demo* pDemo;
public:
ContainerDemo(int x) :pDemo(new Demo(x)) {}
};
2.2 被继承
如果直接继承:
class DerivedDemo :public Demo
{
public:
DerivedDemo(int x) :Demo(x) {}
};
int main()
{
{
DerivedDemo d(1);//怎么确保其基类的数据(此处为Demo.x)保存在堆内
}
system("pause");
return 0;
}
上述程序并不会报错,但是子类时在栈内生成,怎么确保其基类的数据(此处为Demo.x)保存在堆内,即我就想让Demo类作为基类时其内容也必须保存在堆内,怎么办?
在《More Effective C++》里的解决方案是设置一个查询是否在堆内生成的虚基类,具体实现为:
#include<iostream>
#include<list>
#include<exception>
using namespace std;
class HeapTracked
{
public:
HeapTracked(){}
virtual ~HeapTracked() = 0;
bool isOnHeap();
static void* operator new(size_t size);
static void operator delete(void* ptr);
class missingAddress;
private:
typedef const void* rawAddress;
static list<rawAddress> addrList;
};
class HeapTracked::missingAddress :public exception
{
const char* what()
{
return "没找到该地址对象";
}
};
void* HeapTracked::operator new(size_t size)
{
void* addr = ::operator new(size);
addrList.push_front(addr);
return addr;
}
void HeapTracked::operator delete(void* ptr)
{
list<rawAddress>::iterator it = find(addrList.begin(), addrList.end(), ptr);
if (it != addrList.end())
{
addrList.erase(it);
::operator delete(ptr);
}
else
throw missingAddress();
}
bool HeapTracked::isOnHeap()
{
rawAddress addr = dynamic_cast<rawAddress>(this);
list<rawAddress>::iterator it = find(addrList.begin(), addrList.end(), addr);
return it != addrList.end();
}
class Demo:public HeapTracked
{
public:
Demo(int x)
{
this->x = x;
}
//外部不能访问析构函数,因此需要在内部打开一个缺口,访问析构函数
//delete是先执行析构函数,然后释放内存
void destroy()
{
delete this;
}
void get()
{
cout << x << endl;
}
void set(int x)
{
this->x = x;
}
protected:
~Demo() {};//可以被继承,但是限制外部调用该析构函数在栈上生成对象
private:
int x;
};
class DerivedDemo :public Demo
{
public:
DerivedDemo(int x) :Demo(x)
{
if (this->isOnHeap() == false)
{
cout << "父类不在堆内" << endl;
throw 1;
}
}
};
int main()
{
DerivedDemo* d = new DerivedDemo(1);
system("pause");
return 0;
}
但是上述程序在VS2017环境下编译失败: