《C++PP》学习笔记10第十二章类和动态内存分配

98 阅读1分钟

复制构造函数

它接受一个指向类对象的常量引用作为参数,例如

StringBad(const StringBad &);

何时调用

:新建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用。

假设motto是一个StringBad对象,则下面4种声明都将调用复制构造函数

StringBad ditto(motto);
StringBad metoo = motto;
StringBad also = StringBad(motto);
StringBad * pStringBad = new StringBad(motto);

当函数按值传递对象或函数返还对象时,都将使用复制构造函数。(按值传递意味着创建原始变量的一个副本,编译器生成临时对象时,也将使用复制构造函数)

默认的复制构造函数的功能

默认的复制构造函数逐个复制非静态成员的值

定义一个显式复制构造函数以解决问题

StringBad::StringBad(const StringBad & st)
{
num_strings++;
len = st.len;
str = new char[len + 1];
std::strcpy(str,st.str);
cot << num_strings;
}

必须定义复制构造函数的原因在于,一些类成员是使用new初始化的,指向数据的指针,而不是数据本身。

解决赋值的问题

StringBad & StringBad::operator=(const StringBad & st)
{
if(this == &st)
    return *this;
delete [] str;
len = st.len;
str = new char [len + 1];
std::strcpy(str,st.str);
return *this;
}

比较成员函数

bool operator<(const String &st1 , const String &str2)
{
if(std::strcmp(str1.str,str2.str)<0)
   return true;
else
   return false;
}
bool operator>(const String &str1 , const String &str2)
{
return str2 < str1;
}
bool operator==(const String &str1 , const String &str2)
{
return (std::strcmp(str1.str,str2.str) == 0);
}

使用中括号访问字符

char & String::operator[](int i)
{
return str[i];
}
const ```` const
{
...
}

静态类成员函数

static int Howmany() { return num_strings;}

静态类成员函数不与特定的对象相关联,因此只能使用静态数据成员。

在构造函数中使用new的注意事项

(1)构造函数使用new,则析构函数使用delete

(2)new对应delete,new[]对应delete[]

(3)如果有多个构造函数,构造函数不能既有new又有new[]因为析构函数只有一个

(4)应定义一个复制构造函数,通过深度复制将一个对象初始化为另一个对象,通常与下面相似

String::String(const String & st)
{
num_strings++;
len = st.len;
str = new char [len + 1];
std::strcpy(str,st.str);
}

(5)应当定义一个赋值运算符,通过深度复制将一个对象复制给另一个对象,与下面类似

String & String::operator=(const String & st)
{
if(this = &st)
   return *this;
delete[] str;
len = st.len;
str = new char [len + 1];
std::strcpy(str,st.str);
return *this;
}

再谈定位new运算符

char * buffer = new char[BUF];
pc1 = new(buffrer) JustTesting;
pc2 = new JustTesting("Heap1",20);
pc3 = new (buffer) JustTesting("Bad Idea",6);

可以delete pc2但不能delete pc1/pc3因为delete可与常规new运算符配合使用但不能与定位运算符配合使用。

队列类

class Queue
{
private:
struct Node{Item item;struct Node * next;};
enum{Q_SIZE = 10};
Node * front;
Node * rear;
int items;
const int qisze;
..
public:
..
}

qsize初始化不能如同普通变量一样,只能初始化不能赋值。

Queue::Queue(int qs) : qsize(qs)
{
front = rear = NULL;
items = 0;
}

Queue:Queue(int qs) : qszie(qs) , front(NULL) , rear(NULL) , items(0)
{}

对于const类成员和被声明为引用的类成员必须使用这种语法

class Agency{}
class Agent
{
private:
   Agency & belong;
   ..
};
Agent::Agent(Agency & a) : belong(a){...}

入队方法

bool Queue::enqueue(const Item & item)
{
if(isfull())
   return false;
Nod * add = new Node;
add->item = item;
add->next = NULL;
items++;
if(front == NULL)
   front = add;
else
   rear->next = add;
rear = add;
return true;
}

出列方法

bool Queue::dequeue(Item & item)
{
if (front == NULL)
   return false;
item = front->item;
items--;
Node * temp = front;
front = front->next;
delete temp;
if(items == 0)
   rear = NULL;
return true;
}

析构函数

Queue::~Queue()
{
Node * temp;
while(front != NULL)
{
temp = front;
front = front->next;
delete temp;
}
}