使用new操作符可以在程序运行时分配所需的内存
l 动态内存和类
eg:
#include <iostream>
#ifndef STRNGBAD_H_
#define STRNGBAD_H_
class StringBad
{
private:
char * str; // pointer to string
int len; // length of string
static int num_strings; // number of objects
public:
StringBad(const char * s); // constructor
StringBad(); // default constructor
~StringBad(); // destructor
// friend function
friend std::ostream & operator<<(std::ostream & os,
const StringBad & st);
};
#endif
说明:类使用了char指针和静态数据成员。
以下是类方法
#include <cstring> // string.h for some
#include "strngbad.h"
using std::cout;
// initializing static class member
int StringBad::num_strings = 0;
// class methods
// construct StringBad from C string
StringBad::StringBad(const char * s)
{
len = std::strlen(s); // set size
str = new char[len + 1]; // allot storage
std::strcpy(str, s); // initialize pointer
num_strings++; // set object count
cout << num_strings << ": \"" << str
<< "\" object created\n"; // For Your Information
}
StringBad::StringBad() // default constructor
{
len = 4;
str = new char[4];
std::strcpy(str, "C++"); // default string
num_strings++;
cout << num_strings << ": \"" << str
<< "\" default object created\n"; // FYI
}
StringBad::~StringBad() // necessary destructor
{
cout << "\"" << str << "\" object deleted, "; // FYI
--num_strings; // required
cout << num_strings << " left\n"; // FYI
delete [] str; // required
}
std::ostream & operator<<(std::ostream & os, const StringBad & st)
{
os << st.str;
return os;
}
#include <iostream>
using std::cout;
#include "strngbad.h"
void callme1(StringBad &); // pass by reference
void callme2(StringBad); // pass by value
使用类实例(红色部分为解释或相应的输出结果)
int main()
{
using std::endl;
StringBad headline1("Celery Stalks at Midnight");
此处输出:
1:”Celery Stalks at Midnight” object created
StringBad headline2("Lettuce Prey");
2:” Lettuce Prey” object created
StringBad sports("Spinach Leaves Bowl for Dollars");
3:” Spinach Leaves Bowl for Dollars” object created
cout << "headline1: " << headline1 << endl;
此处重载了”<<”符号,输出结果为
headline1: Celery Stalks at Midnight
cout << "headline2: " << headline2 << endl;
headlin2: Lettuce Prey
cout << "sports: " << sports << endl;
sports: Spinach Leaves Bowl for Dollars
callme1(headline1);
String passed by reference:
“Celery Stalks at Midnight”
cout << "headline1: " << headline1 << endl;
headline1: Celery Stalks at Midnight
callme2(headline2);
String passed by value:
“Lettuce Prey”
“Lettuce Prey”deleted, 2 left
此处打印“Lettuce Prey”deleted, 2 left是调用析构函数的结果。调用析构函数的原因是headline2的参数赋给callme2()函数的形参sb时,会调用复制构造函数。函数调用后,要删除sb,此时便会调用析构函数。
cout << "headline2: " << headline2 << endl;
headline2:D 0
此处headline2:后出现的是乱码。这是因为callme2()调用引起的复制构造函数的调用。因为默认情况复制构造函数只执行浅复制。这导致headline2和sb类的char指针指向同一个地址。当调用析构函数后,删除了sb,实际上也删除了headline2中char指针。
cout << "Initialize one object to another:\n";
Initialize one object to another:
StringBad sailor = sports;
说明:此处亦调用了复制构造函数,初始化类有可能调用了赋值操作符,也有可能没有。此处实现没有调用赋值操作符,因为如果调用了的话,复制构造函数会创建一个中间临时对象,而删除临时对象后会导致析构函数调用。
cout << "sailor: " << sailor << endl;
sailor: Spinach Leaves Bowl for Dollars
cout << "Assign one object to another:\n";
Assign one object to another:
StringBad knot;
3:”C++” default object created
knot = headline1;
说明,此处调用的是默认的赋值操作符
cout << "knot: " << knot << endl;
knot: Celery Stalks at Midnight
cout << "End of main()\n";
End of main()
return 0;
}
“Celery Stalks at Midnight” object deleted,2 left
“Spinach leaves Bowl for Dollars” object deleted,1 left
“Spinach leaves Bowl for Doll8 ” object deleted,0 left
“@g” object deleted,-1 left
“-|” object deleted,-2 left
最后两个异常的原因和上面介绍的一样,复制构造函数和默认的赋值操作符都是浅复制。使指针在复制前后都是指向同一个地方。
void callme1(StringBad & rsb)
{
cout << "String passed by reference:\n";
cout << " \"" << rsb << "\"\n";
}
void callme2(StringBad sb)
{
cout << "String passed by value:\n";
cout << " \"" << sb << "\"\n";
}
C++为类构造函数提供了一种可用来初始化数据成员的特殊句法。
eg:queue(int qs):qsize(qs),items(0),front(NULL),rear(NULL){}
如果数据是非静态const成员或引用,则必须采用这种格式。