61.动态内存和类

程序清单12.1 strngbad.h

#pragma once
//strngbad.h -- 有缺陷的string类定义
#include <iostream>
#ifndef STRNGBAD_H_
#define STRNGBAD_H_
class StringBad
{
private:
	char * str;//指向字符串的指针
	int len;//字符串长度
	static int num_strings;//对象数量
public:
	StringBad(const char* s);//构造函数
	StringBad();//默认构造函数
	~StringBad();//默认的析构函数
	//友元函数
	friend std::ostream & operator << (std::ostream & os, const StringBad & st);
};
#endif

  StringBad这个类时使用动态内存分配来开发类的第一个阶段,正确地完成了一些显而易见的工作,例如,在构造函数和析构函数中正确地使用了new和delete。这个类没什么错误,但忽略了一些不明显却不可少的东西。

  对这个声明,需要注意的有两点。首先,它使用char指针(而不是char数组)来表示姓名。这意味着类声明没有为字符串本身分配存储空间,而是在构造函数中使用new来为字符串分配空间。这避免了在类声明中预先定义字符串的长度。

  其次,将num_strings成员声明为静态存储类。静态存储成员有一个特点:无论创建了多少对象,程序都只创建一个静态类变量副本。也就是说,类的所有对象共享同一个静态成员。

程序清单12.2 strngbad.cpp

#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS 1

//strngbad.cpp -- StringBad类方法
#include <cstring>
#include "strngbad.h"
using std::cout;

//初始化static类成员;
int StringBad::num_strings = 0;

//类方法
StringBad::StringBad(const char* s)//构造函数
{
	len = std::strlen(s);//设置尺寸
	str = new char[len + 1];//分配存储空间
	std::strcpy(str, s);//初始化指针
	num_strings++;//设置对象数量
	cout << num_strings << ":\"" << str
		<< "\"对象创建\n";//提示信息
}

StringBad::StringBad()//默认构造函数
{
	len = 4;
	str = new char[4];
	std::strcpy(str, "C++");//默认字符串
	num_strings++;
	cout << num_strings << ":\"" << str
		<< "\" 默认对象创建\n";//提示信息
}

StringBad::~StringBad()//默认的析构函数
{
	cout << "\"" << str << "\"对象删除,";//提示信息
	--num_strings;
	cout << num_strings << " 左\n";
	delete[] str;
}

//友元函数
std::ostream& operator << (std::ostream& os, const StringBad& st)
{
	os << st.str;
	return os;
}

  不能在类中初始化静态成员变量,这是因为声明描述了如何分配内存,但不分配内存。可以用这种格式创建对象,从而分配和初始化内存。对于静态成员,可以在类声明之外使用单独的语句进行初始化,这是因为静态成员变量是单独存储的,不是对象的组成部分。

  初始化是在方法文件中,而不是在类声明文件中进行的,这是因为类声明位于头文件中,程序可能降头文件包括在其他几个文件中,如果在头文件中进行初始化,将出现多个初始化语句副本,从而引发错误。

  对于不能在类声明中初始化静态成员的一种例外情况是,静态成员为const整数或枚举型。

  字符串单独保存在堆内存中,对象仅保存了指出到哪里去查找字符串的信息。

str = s;

这只保存了地址,而没有创建字符串副本,不能这样做。

程序清单12.3vegnews.cpp

//2023年2月26日22:21:22
//vegnews.cpp -- 使用new和delete
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using std::cout;
#include "strngbad.h"

void callme1(StringBad&);//传递引用
void callme2(StringBad);//传递值

int main()
{
	using std::endl;
	{
		cout << "Starting an inner block.\n";
		StringBad headline1("Celery Stalks at Midnight");
		StringBad headline2("Lettuce Prey");
		StringBad sports("Spinach Leaves Bowl for Dollars");
		cout << "headline1: " << headline1 << endl;
		cout << "headline2: " << headline2 << endl;
		cout << "sports: " << sports << endl;
		callme1(headline1);
		cout << "headline1: " << headline1 << endl;
		callme2(headline2);
		cout << "headline2: " << headline2 << endl;
		cout << "Initialize one object to another:\n";
		StringBad sailor = sports;
		cout << "sailor: " << sailor << endl;
		cout << "Assign one object to another:\n";
		StringBad knot;
		knot = headline1;
		cout << "kont:" << knot << endl;
		cout << "Exiting the block.\n";
	}
	cout << "End of main()\n";

	system("pause");
	return EXIT_SUCCESS;
}

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";
}
posted @ 2023-03-09 22:44  CodeMagicianT  阅读(23)  评论(0编辑  收藏  举报