草庐IT

C++类和对象练习

LOST P 2023-04-08 原文

1.设计一个立方体类 Box,它能计算并输出立方体的体积和表面积

要求:
(1)包含成员变量 m_a(立方体边长)。
(2)包含函数 SetA(doublea)(设置立方体边长)、GetVolume()(计算体积)、GetArea()(计算表面积)。
(3)包含函数 Display(),用来输出计算的结果。
(4)设计测试用主函数 main(),用来测试 Box 类。

#include<iostream>
using namespace std;
class Box
{
public:
	double m_a;
	void SetA(double);
	double GetVolume();
	double GetArea();
	void Display();
};

void Box::SetA(double x)
{
	m_a = x;
}

double Box::GetVolume()
{
	return m_a * m_a * m_a;
}

double Box::GetArea()
{
	return m_a * m_a * 6;
}

void Box::Display()
{
	cout << "体积:" << this->GetVolume() << "面积:" << this->GetArea() << endl;
}
int main()
{
	double a;
	cin >> a;
	Box object1;
	object1.SetA(a);
	object1.Display();
	return 0;
}

2. 创建一个带非缺省构造函数和析构函数的类,这些函数都显示一些信息来表示它们的存在。写一段代码验证构造函数与析构函数何时被调用。

#include<iostream>
using namespace std;
class A {
public:
	int a;
	A(int x) 
	{
		a = x;
		cout << "含参构造" << endl;
	}
	A() 
	{
		a = 0;
		cout << "无参构造" << endl;
	}
	A(const A& x) 
	{ 
		cout << "拷贝构造" << endl;
	}
	~A() 
	{ 
		cout << "析构" << this->a << endl;
	}
};
int main() {
	A a1(100), a2 = a1, a3;
	a2.a = 200, a3.a = 300;
	return 0;
}

3. 写一个有拷贝构造函数的类,在拷贝构造函数里用 cout 打印一些信息。写一个函数,这个函数通过传值方式传入新类的对象。写另一个函数,在这个函数内创建这个新类的局部对象,通过传值方式返回这个对象。在 main 函数中调用这些函数以证明通过传值方式传递和返回对象时,拷贝构造函数确实悄悄地被调用了

#include<iostream>
using namespace std;
class A {
public:
	int a;
	A(int x) {
		a = x;
		cout << "含参构造" << endl;
	}
	A() {
		a = 0;
		cout << "无参构造" << endl;
	}
	A(const A& x) { cout << "拷贝" << endl; }
	~A() { cout << "析构" << endl; }
};
A t1(A x) {
	cout << "t1(函数通过传值方式传入新类的对象)" << endl;
	return x;
}
void t2(A x) {
	A aa;
	aa = t1(x);//对位拷贝不调用拷贝构造函数,这里是关于运算符重载的问题
	cout << "t2(创建这个新类的局部对象,通过传值方式返回这个对象)" << endl;
}
int main() {
	A a1(100), a2, a3 = a1;
	cout << endl;
	t1(a1);
	cout << endl;
	t2(a1);
	cout << endl;
	return 0;
}

4. 编写一个 Person 类

包括:
(1)普通数据成员:姓名(char *类型),性别,年龄。
(2)三个构造函数:无参数构造函数,有参数构造函数(参数:姓名,年龄,性别),拷贝构造函数。
(3)析构函数,输出人员信息函数 print()。
(4)编写 main()函数,分别调用三种构造函数,创建三个对象 P1、P2、P3,其中 P3 的创建是用 P2 通过深拷贝复制得到的。

#include<iostream>
using namespace std;
class Person
{
public:
	char* name;
	char gender;
	int age;
	Person();
	Person(char*, char,int);
	Person(const Person& x);
	~Person();
	void print();
};

Person::Person()
{
	age = -1;
}

Person::Person(char* n, char g, int a)
{
	name = n;
	gender = g;
	age = a;
}

Person::Person(const Person& x)
{
	name = new char[100];
	int len = strlen(x.name);
	for (int i = 0; i < len; i++)
	{
		name[i] = x.name[i];
	}
	name[len] = '\0';
	gender = x.gender;
	age = x.age;
}

Person::~Person()
{
	if (this->age == -1)
		cout << "error" << endl;
	else
		this->print();
}

void Person::print()
{
	cout << this->name << " " << this->gender << " " << this->age << endl;
}
int main() {
	char s1[4] = "Bob";
	char s2[4] = "Baa";
	Person p1(s1, 'm', 9), p2, p3 = p1;
	p3.name = s2;
	return 0;
}

注意:

①深拷贝的写法
const char* s = "asdfg";
③char*s可以直接用字符数组的首地址赋值
④字符数组结尾符’/0’

5.设计一个学生类,保证这个类最多只有一个实例(不可能创建多个类实例),并提供一个访问这个实例的接口函数。

(提示:创建实例通常通过构造函数完成,如何定义构造函数才能保证别人不能随便创建实例?)

#include<iostream>
using namespace std;
class Student
{
public:
	static Student *Create();
	int data;
private:
	Student();
	static Student* p;
};
Student* Student::p = nullptr;
Student* Student::Create()
{
	if (p == nullptr)
	{
		p = new Student();
	}
	return p;
}

Student::Student()
{
	p = nullptr;
	data = 0;
}

int main() {
	Student* p1, * p2;
	p1 = Student::Create();
	p2 = Student::Create();
	cout << p1->data << endl;
	p1->data++;
	cout << p2->data;
	return 0;
}

注意:

Student* Student::p = nullptr;必须要有
②p放在private或public中均可,但是构造函数必须放在private中
③两个Static必须要有

6.设计一个类 Stud

包括:
(1)数据成员:学号、姓名和成绩,以及两个静态变量分别存放总分和人数。
(2)有两个普通成员函数 SetData()和 Disp(),分别用于给数据成员赋值和输出数据成员的值。另有一个静态成员函数 Avg(),它用于计算平均分。
(3)一个友元函数 Compare(),用于比较两个学生成绩高低。
(4)在 main()函数中定义一个对象数组并完成对对象的初始化,并求出最高分和最低分的学生

#include<iostream>
using namespace std;
class Student
{
public:
	static int num, sum_grade;
	int number, grade;
	string name;
	void SetData(int, int, string);
	void Disp();
	void Avg();
	void Compare(Student);
};
int Student::num = 0;
int Student::sum_grade = 0;
int main() {
	Student class1[4];
	string names[4] = { "aa","bb","cc" };
	int numbers[4] = { 1,2,3 };
	int grades[4] = { 82,99,98 };
	for (int i = 0; i < 3; i++)
	{
		class1[i].SetData(numbers[i], grades[i], names[i]);
	}
	class1[0].Avg();
	class1[0].Compare(class1[1]);
	class1[0].Disp();
	return 0;
}

void Student::SetData(int nu, int gr, string nam)
{
	number = nu, grade = gr;
	name = nam;
	num++;
	sum_grade += gr;
}

void Student::Disp()
{
	cout << number << ' ' << name << ' ' << grade << endl;
}

void Student::Avg()
{
	float aws = 0;
	aws = sum_grade / num;
	cout << "平均分:" << aws << endl;
}

void Student::Compare(Student x)
{
	if (grade > x.grade)
	{
		cout << name << "分数较高" << endl;
	}
	else if(grade < x.grade)
	{
		cout << x.name << "分数较高" << endl;
	}
	else
	{
		cout << "两者一样高" << endl;
	}
}

注意:

static必须在外部初始化int Student::num = 0;

7. 写一个包含重载的运算符+、- 、*、/和赋值符的 number 类。出于效率考虑,为这些函数合理地选择返回值以便以链式写表达式。

#include<iostream>
using namespace std;
class A {
public:
	int n;
	A(int r)
	{
		n = r;
	}
	A()
	{
		n = 0;
	}
	A operator+(const A& r) {
		A c;
		c.n = n + r.n;
		return c;
	}
	A operator-(const A& r) {
		A c;
		c.n = n - r.n;
		return c;
	}
	A operator*(const A& r) {
		A c;
		c.n = n * r.n;
		return c;
	}
	A operator/(const A& r) {
		A c;
		c.n = n / r.n;
		return c;
	}
	//++a:前缀++返回++之后的值,因此通常返回类对象本身(返回类型为引用)
	A& operator ++ () {
		n++;
		return *this;
	}
	//a++:需要返回++之前的值,因此函数通常返回对象的一个copy(返回类型非引用)
	A operator ++ (int) {
		A s = *this;
		n++;
		return s;
	}
	//如果返回值不是引用,(a=b)=c中,a=b返回的不是a本身,而是一个临时变量,那么(a=b)=c相当于c的值最后没有赋值给a
	A& operator=(const A& r) {
		n = r.n;
		return *this;
	}
};
int main()
{
	A a1(1), a2(2), a3(3);
	a3++;
	cout << a3.n << ' ';
	++a3;
	cout << a3.n << ' ';
	(a1 = a2) = a3;
	cout << a1.n << endl;	
	return 0;
}

注意:

①++a:前缀++返回++之后的值,因此通常返回类对象本身(返回类型为引用)
②a++:需要返回++之前的值,因此函数通常返回对象的一个copy(返回类型非引用)
③如果返回值不是引用,(a=b)=c中,a=b返回的不是a本身,而是一个临时变量,那么(a=b)=c相当于c的值最后没有赋值给a
④+、-、*、/返回的总是临时变量的值,不能返回this的值,否则运算的本质将会发生改变

8. 设计一个 Rational 类,进行带分数的运算。要求:

(1)包含两个整数成员变量表示分子和分母。
(2)包含一个对所声明对象初始化的构造函数。不提供参数时,构造函数应提供默认值。分数存放成简化形式,例如分数“2/4”应在对象中存放成分子 1 和分母 2 的形式。
(3)对下列情况提供 public 成员函数:
a)两个 Rational 值相加,结果保存成简化形式。
b)两个 Rational 值相减,结果保存成简化形式。
c)两个 Rational 值相乘,结果保存成简化形式。
d)两个 Rational 值相除,结果保存成简化形式。
e)按 a/b 形式打印 Rational 值,其中 a 为分子,b 为分母。
(4)编写主函数,测试 Rational 类。
(5)将上述成员函数改为运算符重载的形式,分别作为成员函数和友元函数实现上述功能
成员函数:

#include<iostream>
using namespace std;
class Rationa
{
private:
	int zi, mu;
public:
	Rationa();
	Rationa(int,int);
	Rationa jianhua();
	friend Rationa operator+(Rationa r, Rationa s);
	Rationa operator-(const Rationa&);
	Rationa operator*(const Rationa&);
	Rationa operator/(const Rationa&);
	void disp();
};

Rationa::Rationa()
{
	zi = 1, mu = 1;
}

Rationa::Rationa(int z, int m)
{
	zi = z, mu = m;
}

Rationa Rationa::jianhua()
{
	int m = min(zi, mu);
	for (int i = m; i > 0; i--)
	{
		if (zi % m == 0 && mu % m == 0)
		{
			zi /= m, mu /= m;
			return *this;
		}
	}
	return *this;
}

Rationa operator+(Rationa r, Rationa s)
{
	Rationa t1 = r, t2 = s;
	t1.zi *= t2.mu, t1.mu *= t2.mu;
	t2.zi *= t1.mu, t2.mu *= t1.mu;
	t1.zi += t2.zi;
	return t1;
}

Rationa Rationa::operator-(const Rationa& r)
{
	Rationa t = r;
	zi *= t.mu, mu *= t.mu;
	t.zi *= mu, t.mu *= mu;
	t.zi = zi - t.zi;
	t = t.jianhua();
	return t;
}

Rationa Rationa::operator*(const Rationa& r)
{
	Rationa t;
	t.zi = zi * r.zi, t.mu = mu * r.mu;
	t = t.jianhua();
	return t;
}

Rationa Rationa::operator/(const Rationa& r)
{
	Rationa t;
	t.zi = zi * r.mu, t.mu = mu * r.zi;
	t = t.jianhua();
	return t;
}

void Rationa::disp()
{
	if ((zi < 0 && mu < 0) || (zi > 0 && mu > 0) || zi == 0 || mu == 0)
	{
		int i;
	}
	else
	{
		cout << '-';
	}

	*this = this->jianhua();

	if (mu == 1)
	{
		cout << abs(zi) << endl;
	}
	else if (zi == 0)
	{
		cout << 0 << endl;
	}
	else if (mu == 0)
	{
		cout << "error" << endl;
	}
	else
	{
		cout << abs(zi) << '/' << abs(mu) << endl;
	}
}

int main()
{
	Rationa r1(2, 4), r2(36, 9), r3(0, 1), r4(1, 0);
	r1.disp(), r2.disp(), r3.disp(), r4.disp();
	(r1 * r2).disp();
	(r1 / r2).disp();
	(r1 - r2).disp();
	(r1 + r2).disp();
	return 0;
}

9. 定义一个二维方阵类 matrix。通过重载二元运算符“+”、“-”、“*”和一元运算符“~”, 来实现矩阵加、矩阵减、矩阵乘以及矩阵转置。

#include<iostream>
using namespace std;
class matrix {
public:
	int r, c; //r行c列
	int** mem; //矩阵数据
	matrix(int a, int b);//a行b列
	matrix();
	~matrix();
	matrix(const matrix&);
	matrix operator+ (const matrix& m);
	matrix operator- (const matrix& m); 
	matrix operator* (const matrix& m); 
	matrix& operator= (const matrix& m);
	matrix operator~ (); //矩阵转置
	void display(); 
};

matrix::matrix(int a, int b)
{
	r = a, c = b;
	mem = new int* [r];
	for (int i = 0; i < r; i++)
	{
		mem[i] = new int[c];
	}
	//输入矩阵
	for (int i = 0; i < r; i++)
		for (int j = 0; j < c; j++)
			mem[i][j] = i + 1;
}

matrix::matrix()
{
	r = 1, c = 1;
	mem = new int* [r];
	for (int i = 0; i < r; i++)
	{
		mem[i] = new int[c];
	}
	for (int i = 0; i < r; i++)
		for (int j = 0; j < c; j++)
			mem[i][j] = 0;
}

matrix::~matrix()
{
	for (int i = 0; i < r; i++) {
		delete[] mem[i];
	}
	delete[] mem;
}

matrix::matrix(const matrix&t)
{
	r = t.r, c = t.c;
	mem = new int* [r];
	for (int i = 0; i < r; i++)
	{
		mem[i] = new int[c];
	}
	for (int i = 0; i < r; i++)
		for (int j = 0; j < c; j++)
			mem[i][j] = t.mem[i][j];
}

matrix matrix::operator+(const matrix& m)
{
	matrix t(r, c);
	if (r == m.r && c == m.c)
	{	
		for (int i = 0; i < r; i++)
			for (int j = 0; j < c; j++)
				t.mem[i][j] = mem[i][j] + m.mem[i][j];
		return t;
	}
	else
	{
		cout << "error" << endl;
		t.mem = nullptr;
		return t;
	}
}

matrix matrix::operator-(const matrix& m)
{
	matrix t(r, c);
	if (r == m.r && c == m.c)
	{
		for (int i = 0; i < r; i++)
			for (int j = 0; j < c; j++)
				t.mem[i][j] = mem[i][j] - m.mem[i][j];
		return t;
	}
	else
	{
		cout << "error" << endl;
		t.mem = nullptr;
		return t;
	}
}

matrix matrix::operator*(const matrix& m)
{
	matrix t(r, m.c);
	if (c == m.r)
	{
		for (int i = 0; i < t.r; i++)
			for (int j = 0; j < t.c; j++)
				t.mem[i][j] = 0;
		for (int i1 = 0; i1 < r; i1++)
			for (int j1 = 0; j1 < m.c; j1++)
				for (int k1 = 0; k1 < c; k1++)
					t.mem[i1][j1] += (mem[i1][k1] * m.mem[k1][j1]);
		return t;
	}
	else
	{
		cout << "error" << endl;
		t.mem = nullptr;
		return t;
	}
}

matrix & matrix::operator=(const matrix& t)
{
	r = t.r, c = t.c;
	mem = new int* [r];
	for (int i = 0; i < r; i++)
	{
		mem[i] = new int[c];
	}
	for (int i = 0; i < r; i++)
		for (int j = 0; j < c; j++)
			mem[i][j] = t.mem[i][j];
	return *this;
}

matrix matrix::operator~()
{
	matrix t(c, r);
	for (int i = 0; i < r; i++)
		for (int j = 0; j < c; j++)
			t.mem[j][i] = mem[i][j];
	return t;
}

void matrix::display()
{
	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
			cout << mem[i][j] << ' ';
		}
		cout << endl;
	}
	cout << "==========================" << endl;
}
int main()
{
	matrix a1(3, 2), a2(2, 2), a3(2, 2), a4;
	a1.display();
	a2.display();
	(a1 * a2).display();
	(a2 + a3).display();
	(~a1).display();
	a4 = a3 + a2;
	a4.display();
	return 0;
}

注意

①涉及动态分配内存,一定要留意拷贝构造函数、=重载
②二维数组动态分配内存方法
③矩阵乘法代码实现
④重载等号的返回值必须是引用才可实现连等
⑤析构函数释放内存的方法

有关C++类和对象练习的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  3. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  4. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  5. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  6. ruby-on-rails - 未在 Ruby 中初始化的对象 - 2

    我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调

  7. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  8. Ruby——嵌套类和子类是一回事吗? - 2

    下面例子中的Nested和Child有什么区别?是否只是同一事物的不同语法?classParentclassNested...endendclassChild 最佳答案 不,它们是不同的。嵌套:Computer之外的“Processor”类只能作为Computer::Processor访问。嵌套为内部类(namespace)提供上下文。对于ruby​​解释器Computer和Computer::Processor只是两个独立的类。classComputerclassProcessor#Tocreateanobjectforthisc

  9. ruby - 一个 YAML 对象可以引用另一个吗? - 2

    我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的ruby​​yaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir

  10. ruby - 更改 ActiveRecord 中对象的类 - 2

    假设我有一个FireNinja我的数据库中的对象,使用单表继承存储。后来才知道他真的是WaterNinja.将他更改为不同的子类的最干净的方法是什么?更好的是,我很想创建一个新的WaterNinja对象并替换旧的FireNinja在数据库中,保留ID。编辑我知道如何创建新的WaterNinja来self现有FireNinja的对象,我也知道我可以删除旧的并保存新的。我想做的是改变现有项目的类别。我是通过创建一个新对象并执行一些ActiveRecord魔法来替换行,还是通过对对象本身做一些疯狂的事情,或者甚至通过删除它并使用相同的ID重新插入来做到这一点,这是问题的一部分。

随机推荐