实例源代码heap_data_member.cpp
/*************************************
Critter Farm
version: 1.0
-------------------------
Heap Data Member
Demonstrates an object with a dynamically allocated data member
//destructor prototype
//copy constructor prototype
//overloaded assignment op
version: 2.0
date: 2014/07/07 16:40
**************************************/
#include <iostream>
#include <string>
using namespace std;
class Critter
{
public:
Critter(const string& name="", int age = 0);
~Critter(); //destructor prototype
Critter(const Critter& c); //copy constructor prototype
Critter& Critter::operator=(const Critter& c); //overloaded assignment op
void Greet() const;
/* data */
private:
string* m_pName;
int m_Age;
};
Critter::Critter(const string& name, int age)
{
cout << "constructor called." << endl;
m_pName = new string(name);
m_Age = age;
}
Critter::~Critter()
{
cout << "Destructor called." << endl;
delete m_pName;
}
Critter::Critter(const Critter& c)
{
cout << "Copy constructor called." << endl;
m_pName = new string(*(c.m_pName));
m_Age = c.m_Age;
}
Critter& Critter::operator=(const Critter& c)
{
cout << "Overloaded assignment operator called." << endl;
if (this != &c)
{
delete m_pName;
m_pName = new string(*(c.m_pName));
m_Age = c.m_Age;
}
return *this;
}
void Critter::Greet() const
{
cout << "I'm " << *m_pName << " and I'm " << m_Age << " years old." << endl;
cout << "&m_pName: " << &m_pName << endl;
}
void testDestructor();
void testCopyConstructor(Critter aCopy);
void testAssignmentOp();
int main(int argc, char const *argv[])
{
testDestructor();
cout << endl;
Critter crit("Poochie", 5);
crit.Greet();
testCopyConstructor(crit);
crit.Greet();
cout << endl;
testAssignmentOp();
return 0;
}
void testDestructor()
{
Critter toDestroy("Rover", 3); //创建对象在栈中分配内存
toDestroy.Greet();
}
void testCopyConstructor(Critter aCopy)
{
aCopy.Greet();
}
void testAssignmentOp()
{
Critter crit1("crit1", 7);
Critter crit2("crit2", 9);
crit1 = crit2;
crit1.Greet();
crit2.Greet();
cout << endl;
Critter crit3("crit3", 11);
crit3 = crit3;
crit3.Greet();
}
声明与定义析构函数
当对象的数据成员指向堆中的值时,可能产生的问题就是内存泄露。这是因为当对象被删除时,指向堆中值的指针也随之消失。如果堆中的值还存在,那么将造成内存泄露。如果要避免内存泄露,对象应当在销毁之前做好清理工作,删除与之相关的堆中值。幸运的是,有一种称为析构函数的成员函数,它恰好会在对象销毁之前被调用,以便用于执行必要的清理工作。
如果不编写自己的析构函数,则编译器体程序员创建一个默认析构函数,但它并不尝试释放掉任何数据成员可能指向的堆中的内存。对于简单的类而言,这样做通常是没有问题。但是当类中有数据成员指向堆中值时,则应当编写自己的析构函数,以便能在对象消失之前释放与对象相关的堆中内存,避免内存泄露。
Critter::~Critter()
{
cout << "Destructor called." << endl;
delete m_pName;
}
testDestructor()测试了该析构函数。该函数终止时,toDestroy对象即将被销毁。
幸运的是,toDestroy恰好在销毁之前调用其析构函数。析构函数显示Destructor called.
然后删除堆中等于“Rover”的string对象,完成清理工作,并且没有泄露内存。析构函数没有对m_Age数据成员做任何处理。这完全没有问题,因为m_Age是toDestroy的一部分,分配在栈中,会由系统对Critter对象妥善处理。
提示 :如果类在堆中分配内存,则应当编写析构函数来清理与释放堆中的内存。
当对象的数据成员指向堆中的值时,可能产生的问题就是内存泄露。这是因为当对象被删除时,指向堆中值的指针也随之消失。如果堆中的值还存在,那么将造成内存泄露。如果要避免内存泄露,对象应当在销毁之前做好清理工作,删除与之相关的堆中值。幸运的是,有一种称为析构函数的成员函数,它恰好会在对象销毁之前被调用,以便用于执行必要的清理工作。
如果不编写自己的析构函数,则编译器体程序员创建一个默认析构函数,但它并不尝试释放掉任何数据成员可能指向的堆中的内存。对于简单的类而言,这样做通常是没有问题。但是当类中有数据成员指向堆中值时,则应当编写自己的析构函数,以便能在对象消失之前释放与对象相关的堆中内存,避免内存泄露。
Critter::~Critter()
{
cout << "Destructor called." << endl;
delete m_pName;
}
testDestructor()测试了该析构函数。该函数终止时,toDestroy对象即将被销毁。
幸运的是,toDestroy恰好在销毁之前调用其析构函数。析构函数显示Destructor called.
然后删除堆中等于“Rover”的string对象,完成清理工作,并且没有泄露内存。析构函数没有对m_Age数据成员做任何处理。这完全没有问题,因为m_Age是toDestroy的一部分,分配在栈中,会由系统对Critter对象妥善处理。
提示 :如果类在堆中分配内存,则应当编写析构函数来清理与释放堆中的内存。