【OJ题解】《面向对象程序设计C++》| 01


零、前言


为了验证自己是否真正掌握学校所学C++内容,正所谓,能把一个知识点教会别人,才算自己掌握了。故而,在完成作业后,我选择记录自己的解题思路。

若遇到同课程同学,您可以参考思路,对照自己的代码,如果更好的想法欢迎提出来,
 
不建议抄,会封号



一、问题 A: 类设计练习:定义Tree类


1、题目描述


定义一个Tree(树)类,有成员age(树龄),成员函数 grow(int years) 对 age 加上 years,age() 显示 Tree 对象的 age 的值。
下面的程序不完整,请编程完善:

#include <iostream>
using namespace std;

class Tree {

    你写的代码放在这里

};

int main() {
   Tree t;

   t.setages( 3 );
   t.age();

   t.grow( 20 );
   t.age();

   return 0;
}

输入
本题无输入数据
输出
见输出样例


样例输入
NULL

样例输出
3
23


2、解题思路


由题意可知,需要构建一个 Tree 的类,并包含一个私有变量 age;同时含有三个公共函数 grow(int years)setages()age()。其中 grow() 函数用于修改 ages,setages() 函数用于输入 ages,age()函数用于输出当前年龄。


3、AC代码


#include <iostream>
using namespace std;
 
class Tree {
private:
    int ages = 0;				//(1)
 
public:
    void setages(int age)		//(2)
    {
        ages = age;
    }
    void grow(int years)		//(3)
    {
        ages += years;
    }
    void age()					//(4)
    {
        cout<<ages<<endl;
    }
};
 
int main() {
   Tree t;
 
   t.setages( 3 );
   t.age();
 
   t.grow( 20 );
   t.age();
 
   return 0;
}

4、代码解析


  • (1) 设置私有变量 ages 由于变量years 、age 都为 int 类型,所以 ages 也可为 int 类型
  • (2) 由样例输出可知,该函数为 ages 的赋值。
  • (3) grow() 可以理解为 之前年龄 ages + 经过 years 年后,求当前年龄 ages 。所以直接加上即可。
  • (4) 样例输出有两个输出 和两个 age() 函数,因此可以很自然地想到,该函数的作用为输出当前年龄 ages ,所以直接输出即可 。



二、问题 B: 类设计练习:定义点类Point


1、题目描述


定义点类 Point,其中有数据成员 x 和 y,表示点的横坐标与纵坐标。成员函数 double Distance( const Point & ) 的功能是求两点之间的距离。
请完善下面的程序。

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

你写的代码放在这里

int main() {
   Point a, b;

   a.setPoint();  // 这里读入a点的横坐标、纵坐标
   b.setPoint();  // 这里读入b点的横坐标、纵坐标

   cout << a.Distance( b ) << endl;

   return 0;
}

输入
两行:第一行是 点a 的横坐标 和 纵坐标;
第二行是 点b 的横坐标 和 纵坐标。
输出
两点之间的距离,精确到整数部分。


样例输入
0 0
3 4
样例输出
5

2、解题思路


1、由题意可知,setPoint() 用于获取 对象的坐标x,y,直接输入即可。
2、Distance( const Point & )函数用于计算两点间距离,用两点间公式计算并输出即可(头文件有math函数,是一个提示),注意需要用 double 类型,并且 main() 内由一行输出 该函数,说明该函数只是计算,并不输出。


3、AC代码


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

class Point{
private:
    double x,y;

public:
    void setPoint()							//(1)
    {
        cin>>x>>y;
    }
    double Distance(const Point& b)			//(2)
    {
         double s = sqrt((x-b.x) * (x-b.x) + (y - b.y) * (y - b.y));
         return s;
    }
};

int main() {
   Point a, b;

   a.setPoint();  // 这里读入a点的横坐标、纵坐标
   b.setPoint();  // 这里读入b点的横坐标、纵坐标

   cout << a.Distance( b ) << endl;

   return 0;
}

4、代码解析


  • (1) 读取x,y坐标,使用 cin 即可。
  • (2) 使用两点间距离公式计算即可。



三、问题 C: 类设计练习:编写一个stack类.part.1


问题描述


编写一个 stack 栈类,约定:

  1. 封装数据和操作
  2. 数据成员为私有属性,包括:
    data :保存栈内元素,栈元素类型为 int
    tt : 指示栈顶位置
    len : 当前栈空间的大小
  3. 成员函数为公有属性,包括:
    默认构造函数,完成初始化动作,栈的默认大小是 1000 。最后输出一行:constructing
    析构函数只输出一行:destructing
    top( &v ),函数返回如果为真,参数 v 带回栈顶元素的值;函数返回如果为假,参数 v 的值没有变化
    pop(),如果栈不空,弹走栈顶元素;如果栈空,没有动作
    push( v ),如果栈已满,没有动作;如果栈未满,参数 v 的值进栈
    size(),返回当前栈内元素个数,如果栈空,返回 0
    output(),自栈底到栈顶,输出栈内元素,每一个元素后面跟一个空格,作为分隔。最后换行。如果栈空,没有输出

输入
本题需要解释执行的5种命令定义如下:
1 a :表示把元素 a 压入栈
2 :表示弹走栈顶元素
3 :表示读取栈顶元素的值
4 :表示取得当前栈内元素的个数
5 :表示调用 output() 函数
第一行是命令的数量 n
接下来 n 行,每行是一条命令

输出
对第 3、4、5 类命令,输出一行:该命令对应取得的结果

样例输入
10
1 3
1 5
1 7
3
2
4
2
1 9
5
3

样例输出
constructing <---- 默认构造函数输出
7 <---- 当前栈顶元素是7
2 <---- 弹走了7,所以只剩下2个元素
3 9 <---- 弹走了5,压入了9,所以栈内的元素是3,9
9 <---- 栈顶元素是9
destructing <---- 析构函数输出

提示
下面这个测似用例是容易错的情况:
5
1 3
2
2 <---- 这里容易错,就是栈空时调用pop()
3 <---- 这里也容易错,就是栈空时调用top()
5 <---- 这里也容易错,就是栈空时调用output()
输出结果:
1
3
2
2 <---- 这时栈空,pop()无需任何动作
3 <---- 这时栈空,top()函数返回值应该是false。如果这里输出了内容,就是错了
5 <---- 这里栈空,output()无需输出任何内容


解题思路



AC代码


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

class stack{
private:
    int data[1010];
    int tt,len;

public:
    stack()
    {
        int *data = new int[1010];
        tt = -1;
        len = 0;
        cout<< "constructing" <<endl;

    }

    void push(int temp)
    {

        tt++;
        len++;
        data[tt] = temp;

    }

    void pop()
    {
        if(len <= 0) len = 0;
        else
        {
            len-- ;
            data[tt] = -11;
            tt--;
        }
        return ;
    }

    void top()
    {
        if(len<=0)
            return ;
        else
        {
            cout<<data[tt]<<endl;
            return ;
        }
    }

    void size()
    {
        cout<< len <<endl;
    }

    void output()
    {
        if(len <= 0)
            return ;
        else
        {
            for(int i = 0;i<len;i++)
            {
                cout<< data[i] << " ";
            }
            cout<<endl;
        }
    }

    ~stack()
    {
        cout<< "destructing" <<endl;
    }
};

int main() {
    stack s;
    int n ;
    cin>>n;
    while(n--)
    {
        int t;
        cin>>t;

        if(t == 1)
        {
            int temp ;
            cin>>temp;
            s.push(temp);
        }
        else if( t == 2)
            s.pop();
        else if( t == 3)
            s.top();
        else if( t == 4)
            s.size();
        else if( t == 5)
            s.output();

    }

   return 0;
}

4、代码解析


  • (1)
  • (2)
  • (3)
  • (4)



四、问题 D: 类设计练习:设计整型链表类List


问题描述


设计一个整型链表类 List,能够实现链表节点的插入 insert() 、按位置删除节点 deleteByPos() 、按值删除节点 deleteByVAlue() ,以及链表数据的输出操作 print()。
构造函数、析构函数这些都不用说也知道要写的吧。
提示:链表节点用如下结构定义:

// 节点的结构
struct Node {
   int data;
   Node *next;

   Node() {
       data = 0;
       next = nullptr;
   }

   ~Node() { }
};

链表类 List 有一个数据成员 head,类型是 Node *
根据题目要求完善下面的程序:

#include <iostream>
using namespace std;

/// 节点的结构
struct Node {
   int data;
   Node *next;

   Node() {
       data = 0;
       next = nullptr;
  }

  ~Node() { }
};

/// 链表类
class List {
private:
   Node *head;

public:

  你写的代码放在这里

};

int main() {
   List l1;  /// 创建一个空链表对象 l1

   l1.insert( 0, 10 ); /// 在第 0 个节点的后面插入值为 10 的新节点,也即在链表头部插入新的节点
   l1.insert( 0, 66 );
   l1.insert( 1, 292 );  /// 在第 1 个节点的后面插入值为 10 的新节点
   l1.print( );  /// 从头到尾输出链表节点的值,每个值后跟一空格

   l1.deleteByValue( 66 );  /// 删除链表中第一个值为 66 的节点
   l1.print( );

   l1.insert( 2, -2 );  /// 在第 2 个节点的后面插入值为 -2 的新节点
   l1.insert( 1, 3 );  /// 在第 1 个节点的后面插入值为 3 的新节点
   l1.print( );

   l1.deleteByPos( 2 );  /// 删除链表中第2个位置的节点,那么“3”就被删掉了
   l1.print( );

   l1.deleteByValue( 999 );
   l1.print( );

   return 0;
}

输入
本题没有输入数据
输出
见样例输出

样例输入
NULL
样例输出
66 292 10
292 10
292 3 10 -2
292 10 -2
not found data: 999
292 10 -2

解题思路



AC代码


#include <iostream>
using namespace std;

/// 节点的结构
struct Node {
   int data;
   Node *next;

   Node() {
       data = 0;
       next = nullptr;
  }

  ~Node() { }
};

/// 链表类
class List {
private:
   Node *head;

public:
	List()
	{
		head=new Node;
	}

	void insert(int n,int m)
	{
		Node *q,*p;
		q = head;
		for(int i = 0;i <= n;i++)
        {
			if(q->next == nullptr)
            {
                q->next =new Node;
            }
			q = q -> next;
		}
		p = new Node;
		p -> data = m;
		p -> next = q -> next;
		q -> next = p;
	}

	void deleteByPos(int n)
	{
		Node *p = head,*q;

		for(int i = 0;i <= n;i++)
        {
			p=p->next;
		}
		q = p -> next;
		p -> next = q -> next;
		delete q;
    }

	void  deleteByValue(int n)
	{
		Node *q,*p = head;

		while(p -> next -> next)
        {
			p = p -> next;
			if(p -> next -> data == n)
			{
				q = p -> next;
				p -> next = q -> next;
				delete q;
				return ;
            }
		}
		cout << "not found data: "<< n <<endl;
	}

	void print()
	{
		Node *p;

		p = head -> next;

		while(p -> next)
        {
			p = p -> next;
			cout<< p->data << " ";
		}

		cout<<endl;
	}

	~List()
	{
		Node *p=head,*q;
		while(p)
        {
			q=p;
			delete q;
			p=p->next;
		}
	}

};

int main() {
   List l1;  /// 创建一个空链表对象 l1

   l1.insert( 0, 10 ); /// 在第 0 个节点的后面插入值为 10 的新节点,也即在链表头部插入新的节点
   l1.insert( 0, 66 );
   l1.insert( 1, 292 );  /// 在第 1 个节点的后面插入值为 10 的新节点
   l1.print( );  /// 从头到尾输出链表节点的值,每个值后跟一空格

   l1.deleteByValue( 66 );  /// 删除链表中第一个值为 66 的节点
   l1.print( );

   l1.insert( 2, -2 );  /// 在第 2 个节点的后面插入值为 -2 的新节点
   l1.insert( 1, 3 );  /// 在第 1 个节点的后面插入值为 3 的新节点
   l1.print( );

   l1.deleteByPos( 2 );  /// 删除链表中第2个位置的节点,那么“3”就被删掉了
   l1.print( );

   l1.deleteByValue( 999 );
   l1.print( );

   return 0;
}

4、代码解析


  • (1)
  • (2)
  • (3)
  • (4)

ps,本题输出答案虽然与给出答案一致,但一直Wrong Answer ,目前仍找不到原因,有没有佬告知一下。
在这里插入图片描述




五、问题 E: 类对象成员练习:设计工人类Worker


问题描述


设计工人类 Worker,它具有姓名 name,年龄 age,工作部门 Dept,工资 salary,等数据成员。
其中,salary 是 Salary 类的一个对象。
下面的程序拟完成 Worker 类的设计并用静态成员统计工人的人数,请把程序补充完整。
提示:这里成员函数 setXX() 用于设置各分项数据,成员函数 getXX() 用于获取各分项数据,XX 代表数据成员,如 age 对应的成员函数则为 setAge() 和 getAge() 。

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

class Salary {
private:
   double Wage,  //  基本工资
   Subsidy,  // 岗位工资
   Rent,  // 房租
   WaterFee,  // 水费
   ElecFee;  // 电费

public:
   // 初始化工资数据的各分项
   Salary( double i1, double i2=0, double i3=0, double i4=0, double i5=0 ) {
       Wage = i1;
       Subsidy = i2;
       Rent = i3;
       WaterFee = i4;
       ElecFee = i5;
   }

   Salary( ) {   // 初始化工资的各分项数据为0
       Wage = Subsidy = Rent = WaterFee = ElecFee = 0;
   }

   void setWage ( double f ) {
       Wage = f;
   }

   double getWage( ) {
       return Wage;
   }

   void setSubsidy( double f ) {
       Subsidy = f;
   }

   double getSubsidy( ) {
       return Subsidy;
   }

   void setRent( double f ) {
       Rent=f;
   }

   double getRent(){
       return Rent;
   }

   void setWaterFee( double f ) {
       WaterFee=f;
   }

   double getWaterFee( ) {
       return WaterFee;
   }

   void setElecFee( double f ) {
       ElecFee=f;
   }

   double getElecFee( ) {
       return ElecFee;
   }

   // 计算实发工资, 实发工资 = Wage + Subsidy - Rent - WaterFee - ElecFee
   double RealSalary( ) {
       return Wage + Subsidy - Rent - WaterFee - ElecFee;
   }
};

你编写的代码放在这里。Worker 类中应包含一个 Salary 对象作为一个成员

int main(){
   Worker w1( "John", 30, "design" );
   cout << w1.getSalary() << endl;

   Worker w2;
   cout << "the total num is: " << w1.getNum() << endl;
   w2.setName( "Linda" );
   cout << "in w2 the name is: " << w2.getName() << endl;

   // 基本工资  岗位工资  房租  水费  电费
   w2.setSalary( 100000, 400, 300, 200, 100 );
   cout << w2.getSalary() << endl;

   return 0;
}

输入
本题无需读入数据

输出
见输出样例

样例输入
NULL

样例输出
0
the total num is: 2
in w2 the name is: Linda
99800


解题思路


  • 定义一个类Worker,由题目可知,该类需要包含姓名 name,年龄 age,工作部门 Dept,工资 salary,需要注意的是,salary是Salary的一个对象,所以需要 new 一下。
  • 之后便是分别构造各个私有成员的输入和输出。需要注意的是,这里的名字需要与主函数保持一致,否则函数会报错。而在用到 salary 需要调用该类的函数,要注意它们的类型,保持一致,防止报错。
  • 这里有员工编号,或者是说处理员工进程数目,该变量需要定义在 外头,不属于 Worker 的私有成员。调用该类时,进程数量需要加一记录。注意,不要忘记析构函数是,处理员工进程数量需要减去一。

AC代码


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

class Salary {
private:
   double Wage,  //  基本工资
   Subsidy,  // 岗位工资
   Rent,  // 房租
   WaterFee,  // 水费
   ElecFee;  // 电费

public:
   // 初始化工资数据的各分项
   Salary( double i1, double i2=0, double i3=0, double i4=0, double i5=0 ) {
       Wage = i1;
       Subsidy = i2;
       Rent = i3;
       WaterFee = i4;
       ElecFee = i5;
   }

   Salary( ) {   // 初始化工资的各分项数据为0
       Wage = Subsidy = Rent = WaterFee = ElecFee = 0;
   }

   void setWage ( double f ) {
       Wage = f;
   }

   double getWage( ) {
       return Wage;
   }

   void setSubsidy( double f ) {
       Subsidy = f;
   }

   double getSubsidy( ) {
       return Subsidy;
   }

   void setRent( double f ) {
       Rent=f;
   }

   double getRent(){
       return Rent;
   }

   void setWaterFee( double f ) {
       WaterFee=f;
   }

   double getWaterFee( ) {
       return WaterFee;
   }

   void setElecFee( double f ) {
       ElecFee=f;
   }

   double getElecFee( ) {
       return ElecFee;
   }

   // 计算实发工资, 实发工资 = Wage + Subsidy - Rent - WaterFee - ElecFee
   double RealSalary( ) {
       return Wage + Subsidy - Rent - WaterFee - ElecFee;
   }
};

int num = 0;							//(1)
class Worker
{
private:								//(2)
    string name;
    int age;
    string Dept;
    Salary *salary = new Salary();

public:									//(3)
    Worker()
    {
        num++;
    }
    Worker(string n,int a,string D)
    {
        age = age;
        name = n;
        Dept = D;
        num++;
    }

    ~Worker()
    {
        num--;
    }

    int getNum()
    {
        return num;
    }

    void setAge(int a)
    {
        age = a;
    }

    int getAge()
    {
        return age;
    }

    void setName(string n)
    {
        name = n;
    }

    string getName()
    {
        return name;
    }

    void setDept(string D)
    {
        Dept = D;
    }

    string getDept()
    {
        return name;
    }

    void setSalary(double w,double s,double r,double wf,double ef)
    {
        salary -> setWage(w);
        salary -> setSubsidy(s);
        salary -> setRent(r);
        salary -> setWaterFee(wf);
        salary -> setElecFee(ef);
    }

    double getSalary()
    {
        return salary -> RealSalary( );
    }

};

int main(){
   Worker w1( "John", 30, "design" );
   cout << w1.getSalary() << endl;

   Worker w2;
   cout << "the total num is: " << w1.getNum() << endl;
   w2.setName( "Linda" );
   cout << "in w2 the name is: " << w2.getName() << endl;

   // 基本工资  岗位工资  房租  水费  电费
   w2.setSalary( 100000, 400, 300, 200, 100 );
   cout << w2.getSalary() << endl;

   return 0;
}


4、代码解析


  • (1) 定义员工变量,该变量需要为全局变量,注意初始化为0,防止意外。
  • (2) 分别声明各个私有成员,年龄为整数型,用 int 即可。注意 salary 为 Salary 类的一个对象,所以需要 new 一下。
  • (3) 声明各公有函数,注意变量名需要与 已知函数名(main 函数、以及 Salary 内函数)保持一致,否则会报错。
  • (4) 如果就本题而言,其实有很多的函数可以不需要写出来,如setAge()getAge()setDept()getDept()。但我们不是为了过题而过,是需要保证编程的合理合法完整性。



  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

湫喃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值