类和动态内存分配(1)

String类的编写

// class.h

#pragma once

#ifndef _CLASS_H_
#define _CLASS_H_

#include<iostream>
using std::istream;
using std::ostream;

class String
{
private:
	char* str;   //字符串指针,此处没有分配内存,后续用new来为其开辟内存空间
	int len;
	static int num_strings;  //只有static,则必须声明后在实现文件中进行初始化
	static const int CINLIM = 80; //const static 可以直接在类中初始化
public:
	String(const char* s);
	String();
	String(const String& s);//赋值构造函数
	~String(); //在使用new的类中十分重要 -- 配套使用delete来释放堆空间
	int length() const
	{
		return len;
	};
	String& operator=(const String&st); //对象赋值
	String& operator=(const char*s);  //一般字符串赋值
	char& operator[](int i); //重载 中括号[] 运算符   //可改变数据版本
	const char& operator[](int i)const;  //不改变数据版本
	friend bool operator<(const String& st1, const String& st2);
	friend bool operator>(const String& st1, const String& st2);
	friend bool operator==(const String& st1, const String& st2);
	friend istream& operator>>(istream &is, String& st);  // cin>>
	friend ostream& operator<<(ostream &os, const String& st);  // cout<<
	//静态函数
	static int HowMany();
};

#endif



// fuc.cpp

#include<cstring>   // strcpy--复制字符串, strcmp--根据ASCII码值比较字符串,strlen--获取字符串的长度
#include"class.h"
using namespace std;

//为类中声明的static变量初始化,且要声明其所在的类区域
int String::num_strings = 0;

int String::HowMany()
{
	return num_strings;
}

String::String(const char* s)
{
	len = std::strlen(s);  //strlen获取的是字符串除去末尾空字符的长度,所以长度要为 len+1;
	str = new char[len + 1];  //在构造函数中使用new申请堆空间,在析构函数中使用delete释放堆空间
	strcpy(str, s);
	num_strings++;
}

String::String()
{
	len = 4;
	str = new char[len + 1];
	str[0] = '\0';  //设置为空指针,也可为设置为 NULL, nullptr,(void *)0q	
	num_strings++;
}

String::String(const String& s)//复制构造函数
{
	num_strings++; //为新初始化的对象复制,所以可以在总数上加上1
	len = s.len;
	//深度复制:
	str = new char[len + 1];
	strcpy(str, s.str);
}

String::~String() //在使用new的类中十分重要 -- 配套使用delete来释放堆空间
{
	--num_strings;
	delete[] str;
}

String& String::operator=(const String& st) //对象赋值
{
	if (this == &st)  //如果调用对象和参数已经相同
	{
		return *this;
	}
	delete[] str; //先删除之前的内存,防止内存的浪费
	len = st.len;
	//深度复制
	str = new char[len + 1];
	strcpy(str, st.str);
	return *this;  //使得可以进行连续复制操作
}

String& String::operator=(const char* s)  //一般字符串赋值
{
	delete[] str;
	len = strlen(s);
	str = new char[len + 1];
	strcpy(str, s);
	return *this;
}

char& String::operator[](int i) //重载 中括号[] 运算符   //可改变数据版本
{
	return str[i]; //即返回调用对象字符串的第i个字符
}

const char& String::operator[](int i)const//不改变数据版本
{
	return str[i];
}

//友元函数:
bool operator<(const String& st1, const String& st2)
{
	return (strcmp(st1.str, st2.str) < 0);
}

bool operator>(const String& st1, const String& st2)
{
	return st2 < st1;  //直接使用上面刚重载的运算符 逻辑:若语句为: st1>st2,若成立则应当有st2<st1,可以实现函数功能
	//或 return (strcmp(st1.str,st2.str)>0)
}

bool operator==(const String& st1, const String& st2)
{
	return (strcmp(st1.str, st2.str) == 0);
}

istream& operator>>(istream& is, String& st) // cin>>
{
	char temp[String::CINLIM]; //友元函数,不能直接使用类中的静态常量,需要使用作用域解析运算符
	is.get(temp, String::CINLIM); // 相当于cin,get(name,size)
	if (is)
	{
		st = temp;  //使用的重载过的对于常规字符串的赋值运算符
	}
	//while的作用:读取掉剩下的多余出来的字符
	while (is && is.get() != '\n')   // 若输入失败,则istream对象is的值将被置为false;
	{
		continue;
	}
	return is;
}

ostream& operator<<(ostream& os, const String& st)  // cout<<
{
	os << st.str;
	return os;
}


// main.cpp

#include<iostream>
#include"class.h"
const int Arsize = 10;
const int MaxLen = 81;

int main()
{
	using namespace std;
	String name;
	cout << "Hi,what is your name? " << endl;
	cin >> name;  //本质: cin为第一个参数,name为第二个参数

	cout << name << ", please enter up to" << Arsize
		<< " short sayings <empty line to quit>:"
		<< endl;
	String sayings[Arsize];//创建一个类对象数组来储存输入
	char temp[MaxLen];
	int i;
	for (i = 0; i < Arsize; i++)
	{
		cout << i + 1 << ": ";
		cin.get(temp, MaxLen);
		while (cin && cin.get() != '\n') //清除多余的字符
		{
			continue;
		}
		if (!cin || temp[0] == '\0') //实现 empty to quit
		{
			break;
		}
		else
		{
			sayings[i] = temp;
		}
	}
	int total = i; //记录输入的总数

	if (total > 0)
	{
		cout << "Here are your saying: " << endl;
		for (i = 0; i < total; i++)
		{
			//sayings[i][0] sayings[i]对象中的字符串的首字符
			cout << sayings[i][0] << ": " << sayings[i] << endl;
		}
		int shortest = 0;
		int first = 0;
		for (i = 1; i < total; i++)
		{
			if (sayings[i].length() < sayings[shortest].length())  //比较出长度最小的字符串
			{
				shortest = i;
			}
			if (sayings[i]<sayings[first]) //比较出ASCII值最小的字符串
			{
				first = i;
			}
		}
		cout << "shortest sayings: " << sayings[shortest] << endl;
		cout << "First alphabetically: " << sayings[first] << endl;
		cout << "This program used :" << String::HowMany()
			<< " strings objects. Bye~" << endl;
	}
	else
	{
		cout << "No input! Bye~" << endl;
	}

	system("pause");
	return 0;
}

知识点:

1.strcmp(s1,s2)的详细内容:

   1):原型:int strcmp(const char *s1, const char *s2); 头文件:#include <string.h>

   2):若s1>s2,则返回一个大于零的值,若s1=s2(字符串完全相同),则返回一个等于零的值,若s1<s2,则返回一个小于零的值

   3):说明:strcmp()函数是根据ACSII码的值来比较两个字符串的;strcmp()函数首先将s1字符串的第一个字符值减去s2第一个字符,若差值为零则继续比较下去;若差值不为零,则返回差值。

测试代码如下:

#include<iostream>
#include<cstring>
using namespace std;

int main()
{
	const char* a = "abcd";
	const char* b = "aaaa";
	const char* c = "aaaa";
	cout << strcmp(a, b) << endl;  //返回值为1,说明a>b,所以当两个字符串长度相等时,会继续根据ASCII码值进行比较
	cout << strcmp(b, c) << endl;  //只有两个字符串完全相等时,返回值才是0
	const char *L1 = "c fool and his money are soon parted";
	const char* L2 = "penny wise,pound foolish";
	cout << strcmp(L1, L2) << endl; //返回值为-1,说明是strcmp是根据ASCII码值来比较大小的


	system("pause");
	return 0;
}

2.strcmp是用来比较两个字符串的ASCII码值的大小的,若想要比较两个字符串的长度,可以先用strlen()或者string.length()来获取字符串的长度,再进行相应的比较。

3.若类中包含了使用new初始化的指针成员,则应定义一个复制构造函数( 参数为类对象引用的构造函数)以及重载赋值运算符,来实现深度复制(即复制数据的值)。

4.实现深度复制:给指针分配一个新的内存,再把值赋给指针 -- 即实现了值的复制

    1): (char * )str = new char[n]   2): strcpy(str , st.str)

5.空指针的表示方法: str = '\0' = NULL = nullptr = (void *) 0

6.静态类成员函数:在类中的函数声明前加上static -- 不能通过对象访问,而使用类名和作用域解析运算符' :: '来访问。(在实现文件中定义时不用再加上static--与友元函数形式类似)

7.复制构造函数在为新创建的对象初始化时被调用。

8.类中声明的static变量:若为const static,则可以在类中直接初始化,若只是static, 则必须在类中声明后,再去实现文件中进行初始化。(初始化不用再加上static,且要声明其所属于的类)

9. 为类中静态变量初始化:

   1):在类中:static int num_strings;

   2):在实现文件中:int String::num_strings = 0;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值