指向对象的指针
程序员文章站
2024-01-01 17:11:58
...
指向对象的指针
所谓指向对象的指针例如:String* favorite = new String(sayings[某个数]).
这个是利用复制构造函数进行初始化的,调用的是String(const String& ),favorite就是指向被创建的新对象的指针,这个新创建的对象是没有名字的,通过favorite进行管理.
类声明如下:
class String
{
private:
char * str; // 指向字符串的指针
int len; // 字符串长度
static int num_strings; // String类对象个数
static const int CINLIM = 80; // 每个String对象限制输入的字符
public:
// 构造函数和析构函数
String(const char * s); // 构造函数
String(); // 默认构造函数
String(const String &); // 复制构造函数
~String(); // 析构函数
int length () const { return len; } //字符串长度
// 运算符重载函数
String & operator=(const String &);
String & operator=(const char *);
char & operator[](int i);
const char & operator[](int i) const;
// 友元函数
friend bool operator<(const String &st, const String &st2);
friend bool operator>(const String &st1, const String &st2);
friend bool operator==(const String &st, const String &st2);
friend ostream & operator<<(ostream & os, const String & st);
friend istream & operator>>(istream & is, String & st);
// 静态方法
static int HowMany();
静态方法
static int HowMany();
};
int String::num_strings = 0; //静态成员初始化
// 静态类成员函数
// 静态函数的声名带static关键字,但是定义不带
// 静态成员不能够使用this指针
// 若静态成员函数是在公有部分声名的,可以使用域解析运算符直接调用
// 静态成员函数不与特定的对象关联,静态成员函数只能够使用静态成员函数
int String::HowMany()
{
return num_strings;
}
//带参数的构造函数,可作为强制转换,可以直接赋值给String对象,通过这个构造函数String(const char * s).严格意义来上说,"字符串"是一个地址常量,是不能改变字符串中的值,所以这里的参数是const类型的,但是类中的str所指空间是new出来的,相当于一个字符数组,所以说可以改变值.
String::String(const char * s)
{
len = std::strlen(s); // 设置大小
str = new char[len + 1]; // allot storage
std::strcpy(str, s); // initialize pointer
num_strings++; // set object count
}
String::String() // 默认构造函数
{
len = 0;
str = new char[1]; //这条语句与str = new char这条语句表达的意思相同,但是不能和析构函数中的delete [] str匹配.
str[0] = '\0'; // 调用默认构造函数的都是一个空字符串
num_strings++;
}
//复制构造函数
String::String(const String & st)
{
num_strings++; // handle static member update
len = st.len; // same length
str = new char [len + 1]; // allot space
std::strcpy(str, st.str); // copy string to new location
}
String::~String() // necessary destructor
{
--num_strings; // required
delete [] str; // required
}
// 运算符重载函数
// 重写赋值构造函数
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;
}
// 用于强制转换,一个数组char temp[40]中的数组名temp可以直接赋值给对象
/*****************************
String name; //默认构造函数已经初始化了
char temp[40];
cin.getline(temp ,40 ); //输入整行字符
name = temp; //相当于调用nmae.operator=(temp),temp是char*.
*****************************/
String & String::operator=(const char * s)
{
delete [] str; //删除已经初始化的str 的空间
len = std::strlen(s); /****
str = new char[len + 1]; 这三句都是将s所指字符串的值进行深度复制
std::strcpy(str, s); ****/
return *this; //返回调用函数对象
}
// 可以通过某个对象直接访问其中的字符,比如food是String的对象,food[0]可以直接调用[]这个运算符的重载函数,而且因为返回值类型是char& ,所以可以直接给food[0]重新赋值,比如
String = food("might"),food[0] = 'r',第二条语句就是调用operator[](int i)这个重载函数,char& food.operator[](0)其实就是food.str[0]的引用,所以最后就改变了food.str[0]='r'的值.
此方法不保证对象改变.
char & String::operator[](int i)
{
return str[i];
}
// 增加了一个返回常量对象中某个字符的方法
const char & String::operator[](int i) const
{
return str[i];
}
// 友元函数
// String对象之间比较有助于与常规字符串进行比较,比如,"love" == answer就会调用友元函数operator==(const String &st1, const String &st2),因为"love"通过构造函数String(const char * s) 可以进性强制转换,变为String("love").
bool operator<(const String &st1, const String &st2)
{
return (std::strcmp(st1.str, st2.str) < 0); //若strcmp(st1.str, st2.str) < 0则返回1,否则返回0
}
bool operator>(const String &st1, const String &st2)
{
return st2 < st1; //调用友元函数,st1>st2就是st2<st1,所以st2<st1就为>重载函数的运算结果
}
bool operator==(const String &st1, const String &st2)
{
return (std::strcmp(st1.str, st2.str) == 0);
}
// 输出String对象
ostream & operator<<(ostream & os, const String & st)
{
os << st.str;
return os;
}
// 给String通过cout >> 直接赋值
istream & operator>>(istream & is, String & st)
{
char temp[String::CINLIM]; //有限制,字符大小最多为80
is.get(temp, String::CINLIM); //输入一一整行字符<80
if (is) //输入正确
st = temp; //调用st.operator=(temp)重载函数
while (is && is.get() != '\n') 丢弃多余的字符
continue;
return is;
}
主函数执行如下:
#include <iostream>
#include <cstdlib> // (or stdlib.h) for rand(), srand()
#include <ctime> // (or time.h) for time()
#include "string1.h"
const int ArSize = 10;
const int MaxLen = 81;
int main()
{
using namespace std;
String name;
cout <<"Hi, what's your name?\n>> ";
cin >> name;
cout << name << ", please enter up to " << ArSize
<< " short sayings <empty line to quit>:\n";
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') // 是空行,break
break;
else
sayings[i] = temp; // 不是空行调用sayings[i].=operator()
}
int total = i; // 输入多少行
if (total > 0)
{
cout << "Here are your sayings:\n";
for (i = 0; i < total; i++)
cout << sayings[i] << "\n";
// 使用对象指针跟踪最短输入字符串和首字符最大字符串
String * shortest = &sayings[0]; // 初始化第一个数组中第一个对象
String * first = &sayings[0]; //同上
for (i = 1; i < total; i++)
{
if (sayings[i].length() < shortest->length())
shortest = &sayings[i];
if (sayings[i] < *first)
first = &sayings[i];
}
cout << "Shortest saying:\n" << * shortest << endl;
cout << "First alphabetically:\n" << * first << endl;
srand(time(0));
int choice = rand() % total; // 真正的随机数rand(),取余totoal,范围在0~total-1
// 利用new创建了一个新的对象,通过对象指针管理
String * favorite = new String(sayings[choice]);
cout << "My favorite saying:\n" << *favorite << endl; //随机输出一句话
delete favorite; //释放掉的只是str和len所用的存储空间
}
else
cout << "Not much to say, eh?\n";
cout << "Bye.\n";
return 0;
}
运行结果: