C++ primer plus习题及解析第十二章(类和动态内存分配)

题目:12.1

题: 对于下面的类声明:

class Cow
{
private:
	char name[20];
	char* hobby;
	double weight;
public:
	Cow();
	Cow(const char* nm, const char* ho, double wt);//有参构造
	Cow(const Cow& c);//拷贝构造函数
	~Cow();//析构函数
	Cow& operator=(const Cow& c);
	void ShowCow() const;//展示信息


};

给这个类提供实现,并编写一个使用所有成员函数的小程序。 

class Cow
{
private:
	char name[20];
	char* hobby;
	double weight;
public:
	Cow();
	Cow(const char* nm, const char* ho, double wt);//有参构造
	Cow(const Cow& c);//拷贝构造函数
	~Cow();//析构函数
	Cow& operator=(const Cow& c);
	void ShowCow() const;//展示信息


};

Cow::Cow()
{
	cout << "构造函数!!!" << endl;
}
Cow::Cow(const char* nm, const char* ho, double wt)//有参构造
{
	strcpy_s(this->name, nm);//拷贝
	//hobby和ho都是指针,最好给其分配地址了,在进行赋值
	int len = sizeof(ho) / sizeof(ho[0]);
	hobby = new char[len+1];
	hobby[len] = '\0';
	strcpy_s(hobby,len, ho);
	
	this->weight = wt;
}
Cow::Cow(const Cow& c)//拷贝构造函数
{
	//将c中所有的值都拷贝到主体中
	strcpy_s(this->name, c.name);
	
	//指针不能直接赋值,不安全
	int len = sizeof(c.hobby) / sizeof(c.hobby[0]);
	this->hobby = new char[len + 1];
	strcpy_s(this->hobby,len, c.hobby);
	hobby[len] = '\0';
	this->weight = c.weight;

}
Cow::~Cow()//析构函数
{
	delete[] hobby;
	hobby = nullptr;
	cout << "析构函数!!!" << endl;
}
Cow& Cow::operator=(const Cow& c)
{
	//等号赋值操作,这也是拷贝
	strcpy_s(this->name, c.name);
	int len = sizeof(c.hobby) / sizeof(c.hobby[0]);
	this->hobby = new char[len + 1];
	strcpy_s(this->hobby, len, c.hobby);
	hobby[len] = '\0';
	this->weight = c.weight;
	return *this;
}
void Cow::ShowCow() const//展示信息
{
	cout << "name=" << this->name << endl;
	cout << "hobby=" << this->hobby << endl;
	cout << "weight=" << this->weight << endl;
}
void Func()
{
	Cow a;//无参构造函数
	Cow b("牛1", "吃草", 200.0);//有参构造
	b.ShowCow();
	cout << "---------------------------------" << endl;
	Cow c(b);//拷贝构造函数
	c.ShowCow();
	cout << "---------------------------------" << endl;
	Cow e;
	e = b;//等号重载
	e.ShowCow();
}

问题1:Cow(const char* nm, const char* ho, double wt),前两各参数接收的是什么?

 前两个参数接收的是指向字符数组的指针。

 问题2:类中的this是指向本体的指针吗?

是的,this指针是一个隐含的指向当前对象的指针,它指向调用成员函数的对象本体。在类的成员函数中,可以使用this指针来访问对象的成员变量和成员函数。

问题3:char*hobby这个成员指针,为什么输出时候直接用cout<<this->hobby;

 在C++中,char*类型的指针通常指向一个以null结尾的字符串数组。当直接使用cout输出一个char*指针时,cout会输出指针所指向的字符串,直到遇到null终止符为止。因此,当你使用cout << this->hobby;时,实际上是输出了this->hobby所指向的字符串。这种行为是C++中的一种约定俗成的用法,但需要注意确保指针指向的字符串是以null结尾的,否则可能导致未定义的行为。

题目:12.2

题: 通过完成下面的工作来改进String类声明(即将String1.h升级为String2.h)。

a.对+运算符进行重载,使之可将两个字符串合并成1个。

b.提供一个Stringlow( )成员函数,将字符串中所有的字母字符转 换为小写(别忘了cctype系列字符函数)。

c.提供String( )成员函数,将字符串中所有字母字符转换成大写。 d.提供一个这样的成员函数,它接受一个char参数,返回该字符在字符串中出现的次数。使用下面的程序来测试您的工作:

class String2
{
private:
	string ans;

public:
	String2();//无参构造函数

	String2(const string name);//有参构造函数

	String2 operator=(const String2 object);//重载等号操作

	String2 operator+(const String2 object);//重载加号操作

	void Stringlow();//将字符转化为小写字母

	void Stringup();//将字符转化为大写字母

	int  String_Count(char c);//返回该字符在字符串中出现的次数。

	void Print_String();//打印字符

	~String2();//析构函数

};
#include "String2.h"

String2::String2()//无参构造函数
{
	cout << "无参构造函数!!!" << endl;
}

String2::String2(const string name)//有参构造函数
{
	this->ans = name;
}

String2 String2::operator=(const String2 object)//重载等号操作
{
	//就是进行拷贝
	this->ans = object.ans;
	return *this;
}

String2 String2::operator+(const String2 object)//重载加号操作
{
	this->ans = this->ans + object.ans;
	return *this;
}

void String2::Stringlow()//将字符转化为小写字母
{
	string::iterator it = this->ans.begin();
	for (it; it != this->ans.end(); it++)
	{
		*it=tolower(*it);
	}
}

void String2::Stringup()//将字符转化为大写字母
{
	string::iterator it = this->ans.begin();
	for (it; it != ans.end(); it++)
	{
		*it = toupper(*it);
	}
	
}

int  String2::String_Count(char c)//返回该字符在字符串中出现的次数。
{
	int count = 0;
	string::iterator it = this->ans.begin();
	for (it; it != ans.end(); it++)
	{
		if (*it == c)
		{
			count++;
		}
	}
	return count;
}

String2::~String2()//析构函数
{
	cout << "析构函数!!!" << endl;
}

void String2::Print_String()//打印字符
{
	cout << this->ans << endl;
}

 问题1:c++如何大小写字母如何进行转化。

#include <iostream>
#include <cctype>

int main() {
    //转化成小写用tolower()
    char uppercaseLetter = 'A';
    char lowercaseLetter = tolower(uppercaseLetter);

    std::cout << "Uppercase letter: " << uppercaseLetter << std::endl;
    std::cout << "Lowercase letter: " << lowercaseLetter << std::endl;

    //转化成大写用toupper()
    char lowercaseLetter = 'a';
    char uppercaseLetter = toupper(lowercaseLetter);

    std::cout << "Lowercase letter: " << lowercaseLetter << std::endl;
    std::cout << "Uppercase letter: " << uppercaseLetter << std::endl;



    return 0;
}

题目:12.2(优化)

#pragma once
#ifndef STRING2_H_
#define STRING2_H_
#include<iostream>
using namespace std;

class String2
{
private:
	char* str;//指向数组的指针
	int chars;//字符数组大小
	static int strings;//创建了类的个数

public:
	String2();//无参构造函数

	String2(const String2& s);//拷贝构造函数

	String2(const char* ps);//也是赋值的一种,大多要使用strcpy_s()

	~String2();//析构函数

	int numstrings();

	int len();

	void stringup();//转化成大写字母

	void stringlow();//转化成小写字母

	int has(char c);//应该是包含字符数量

	String2& operator=(const String2& s);//重载等号

	void Show_String2();//显示String2中的信息

};

#endif // !STRING2_H_

/*
这段代码是用来防止头文件的重复包含的。当一个头文件被包含多次时,
为了避免重复定义,可以使用这种方式来保护头文件内容只被包含一次。
当第一次包含头文件时,STRING2_H_会被定义,之后再次包含时,STRING2_H_已经被定义,
就不会再次包含头文件内容。这样可以避免出现重复定义的错误。
*/
#include "String2.h"
int String2::strings = 0;//对私有变量进行初始化

String2::String2()//无参构造函数
{
	this->str = NULL;
	this->chars = 0;
	this->strings++;
	cout << "无参构造函数!!!" << endl;
}

String2::String2(const String2& s)//拷贝构造函数
{
	//用实例进行赋值
	this->chars = s.chars;

	//为str申请空间
	str = new char[chars + 1];
	strcpy_s(str, this->chars,s.str);//拷贝给str
	str[chars] = '\0';//结束标识符

	strings++;//实例化个数加一

}

String2::String2(const char* ps)//也是赋值的一种,大多要使用strcpy_s()
{
	//传入的必然是一个数组
	int len = strlen(ps);

	//为str申请空间
	this->str = new char[len + 1];
	strcpy_s(str, len+1, ps);
	str[len] = '\0';
	this->chars = len;
	this->strings++;
}

String2::~String2()//析构函数
{
	strings--;
	delete[]str;//删除所有申请的空间
}

int String2::numstrings()
{
	return strings;
}

int String2::len()
{
	return this->chars;
}

void String2::stringup()//转化成大写字母
{
	for (int i = 0; i < this->chars; i++)
	{
		this->str[i] = toupper(str[i]);
	}
}

void String2::stringlow()//转化成小写字母
{
	for (int i = 0; i < this->chars; i++)
	{
		this->str[i] = tolower(str[i]);
	}
}

int String2::has(char c)//应该是包含字符数量
{
	int count = 0;
	for (int i = 0; i < this->chars; i++)
	{
		if (this->str[i] == c)
		{
			count++;
		}
	}
	return count;
}

String2& String2::operator=(const String2& s)//重载等号
{
	//本质上也是拷贝
	/*int len = strlen(s.str);
	this->str = new char[len + 1];
	strcpy_s(this->str, len, s.str);
	str[len] = '\0';
	this->chars = s.chars;
	this->strings = s.strings;
	return *this;*/

	//上面的想的简单了
	if (this == &s)
		return *this;//如果直接相同了,那就不用进行赋值操作了

	delete[] str;//删除原来的旧值
	chars = s.chars;
	str = new char[chars + 1];
	strcpy_s(this->str, this->chars, s.str);
	this->strings = s.strings;
	return *this;
}

void String2::Show_String2()
{
	cout << "str:";
	for (int i = 0; i < this->chars; i++)
	{
		cout << str[i];
	}
	cout << endl;
	cout << "chars:";
	cout << this->chars << endl;
	cout << "strings:";
	cout << this->strings << endl;
	cout << endl;
}

问题1:指针可以直接当数组使用吗?

指针可以直接当数组使用,因为数组名本身就是一个指向数组首元素的指针。可以通过指针来访问数组中的元素,也可以通过指针进行数组的遍历和操作。但是需要注意的是,指针和数组是不同的类型,指针可以指向数组,但数组本身并不是指针。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值