实验2 类和对象——基础编程1
一、实验目的
加深对类,对象的理解,能够解释类的封装,类的接口
会使用C++语法规则正确定义,实现,测试类,会使用类创建对象,并基于对象编程
针对具体问题场景,练习运用面向对象思维进行设计,合理利用C++语言特性(访问权限控制,static,friend,const),在数据共享和保护之间达到平衡
会用多文件方式组织代码
加深对C++内存资源管理技术的理解,能够解释构造函数,析构函数的用途,分析它们何时会被调用
二、实验准备
类的抽象,设计
使用C++定义类,使用类创建对象的语法;构造/析构陈洁灵语法,用途及调用时机
类的共享与保护机制:访问权限控制,静态成员(static),友元(friend),const
多文件组织代码
三、实验内容
1. 实验任务1
代码:
t.h
1 #pragma once 2 #include <string> 3 4 class T{ 5 public: 6 T(int x = 0, int y = 0); 7 T(const T &t); 8 T(T &&t); 9 ~T(); 10 void adjust ( int ratio ); 11 void display ( )const ; 12 private: 13 int m1,m2; 14 public: 15 static int get_cnt(); 16 17 public: 18 static const std::string doc; 19 static const int max_cnt; 20 private: 21 static int cnt ; 22 23 friend void func(); 24 25 }; 26 void func();
t.cpp
1 #include"t.h" 2 #include<iostream> 3 #include<string> 4 5 using std::cout; 6 using std::endl; 7 using std::string; 8 9 const std::string T::doc{"a simple class sample"}; 10 const int T :: max_cnt= 999; 11 int T::cnt = 0; 12 T ::T (int x,int y) :m1{x},m2{y} 13 { 14 ++cnt; 15 cout << "T constructor called.\n"; 16 } 17 18 T ::T (const T &t) :m1{t.m1},m2{t.m2} 19 { 20 ++cnt; 21 cout << "T copy constructor called.\n"; 22 } 23 24 25 T ::T(T &&t):m1{t.m1},m2{t.m2} 26 { 27 ++cnt; 28 cout << "T move constructor called.\n"; 29 } 30 31 T::~T(){ 32 --cnt; 33 cout << "T destructor called.\n"; 34 35 } 36 void T::adjust(int ratio){ 37 m1*=ratio; 38 m2*=ratio; 39 40 } 41 void T::display ()const 42 { 43 cout<<"("<<m1<<","<<"m2"<<")"; 44 } 45 46 int T::get_cnt() 47 { 48 return cnt; 49 } 50 51 void func() 52 { 53 T t5(42); 54 t5.m2=2049; 55 cout << "t5=";t5.display();cout<<endl; 56 }
task1.cpp
1 #include"t.h" 2 #include<iostream> 3 4 using std::cout; 5 using std::endl; 6 7 void test ( ); 8 9 int main() 10 { 11 test(); 12 cout<<"\nmain:\n"; 13 cout<<"T objects'current count:"<<T::get_cnt()<<endl; 14 15 } 16 17 void test() 18 { 19 cout<<"test class T:\n"; 20 cout<<"T info:"<<T::doc<<endl; 21 cout<<"T objects'max count: "<<T::max_cnt<<endl; 22 cout<<"T objects'current count: "<<T::get_cnt()<<endl<<endl; 23 24 T t1; 25 cout<<"t1 = ";t1.display();cout<<endl; 26 27 T t2(3,4); 28 cout <<"t2 = ";t2.display();cout<<endl; 29 30 T t3(t2); 31 t3.adjust(2); 32 cout<<"t3 = ";t3.display();cout<<endl; 33 34 T t4(std::move(t2)); 35 cout<<"t3 = ";t4.display();cout<<endl; 36 37 cout<<"T objects'current count: "<<T::get_cnt()<<endl; 38 func(); 39 }
运行截图:
问题回答:
问题一:不可以去掉t.h中最后的void func();
friend void func()不可以作为一个完整的函数声明。没有给出函数的参数列表。故还是需要在在t.h最后加上void func();
问题二:构造函数是在对象被创建时利用特定的值构造对象,将对象初始化为一个特定的状态。
普通构造函数是创建一个对象假如有两个参数,就可以接受两个参数,如果没有参数就是使用自定义的默认值,可以是0或者其它。
复制构造函数是一个已经存在的对象创建新的对象的时候调用它,新对象与存在的对象状态相同。
移动构造函数它通过右值引用来实现资源的转移。
调用时机:调用构造函数结束后调用析构函数,析构的顺序与构造的顺序相反。
问题三:
不能正确编译运行
2. 实验任务2
代码:
Complex.h
1 #pragma once 2 #include<string> 3 4 class Complex{ 5 //类属性 6 public: 7 static const std::string doc; 8 Complex(double a=0,double b=0); 9 Complex(const Complex &c); 10 11 12 //对象属性 13 private: 14 double real; 15 double imag; 16 //对象方法 17 public: 18 //接口: 19 const double get_real(); 20 const double get_imag(); 21 Complex add(const Complex& c); 22 //友元函数 23 public: 24 friend Complex add(const Complex &c1,const Complex &c2); 25 friend bool is_equal(const Complex &c1,const Complex &c2); 26 friend bool is_not_equal(const Complex &c1,const Complex &c2); 27 friend void output(const Complex &c); 28 friend double abs(const Complex &c); 29 ~Complex(); 30 }; 31 32 Complex add(const Complex &c1,const Complex &c2); 33 bool is_equal(const Complex &c1,const Complex &c2); 34 bool is_not_equal(const Complex &c1,const Complex &c2); 35 void output(const Complex &c); 36 double abs(const Complex &c);
Complex.cpp
1 #include"Complex.h" 2 #include<iostream> 3 #include<string> 4 #include<cmath> 5 6 7 using std::cout; 8 using std::endl; 9 using std::string; 10 11 12 13 //类属性 14 const std::string Complex::doc={"a simplified complex class"}; 15 Complex::Complex(double a,double b):real(a),imag{b} {}; 16 Complex::Complex(const Complex &c){ 17 real=c.real; 18 imag=c.imag; 19 } 20 //接口 21 const double Complex::get_real(){ 22 return real; 23 24 } 25 const double Complex::get_imag(){ 26 return imag; 27 } 28 Complex Complex::add(const Complex& c) { 29 return Complex(real + c.real, imag + c.imag); 30 } 31 32 33 Complex add(const Complex &c1,const Complex &c2){ 34 Complex c; 35 c.real=c1.real+c2.real; 36 c.imag=c1.imag+c2.imag; 37 return c; 38 39 } 40 bool is_equal(const Complex &c1,const Complex &c2){ 41 if(c1.real==c2.real&&c1.imag==c2.imag) 42 return 1; 43 else 44 return 0; 45 } 46 bool is_not_equal(const Complex &c1,const Complex &c2){ 47 if(c1.real!=c2.real||c1.imag!=c2.imag) 48 return 1; 49 else 50 return 0; 51 } 52 void output(const Complex &c){ 53 if(c.imag<0) 54 cout<<c.real<<c.imag<<"i"; 55 else 56 cout<<c.real<<"+"<<c.imag<<"i"; 57 } 58 double abs(const Complex &c){ 59 return sqrt(c.real*c.real+c.imag*c.imag); 60 } 61 Complex::~Complex()=default;
运行截图:
3. 实验任务3
代码:
1 #include <iostream> 2 #include <complex> 3 4 using std::cout; 5 using std::endl; 6 using std::boolalpha; 7 using std::complex; 8 9 void test() { 10 cout << "标准库模板类comple测试: " << endl; 11 complex<double> c1; 12 complex<double> c2(3, -4); 13 const complex<double> c3(3.5); 14 complex<double> c4(c3); 15 16 cout << "c1 = " << c1 << endl; 17 cout << "c2 = " << c2 << endl; 18 cout << "c3 = " << c3 << endl; 19 cout << "c4 = " << c4 << endl; 20 cout << "c4.real = " << c4.real() << ", c4.imag = " << c4.imag() << endl; 21 cout << endl; 22 23 cout << "复数运算测试: " << endl; 24 cout << "abs(c2) = " << abs(c2) << endl; 25 c1 += c2; 26 cout << "c1 += c2, c1 = " << c1 << endl; 27 cout << boolalpha; 28 cout << "c1 == c2 : " << (c1 == c2) << endl; 29 cout << "c1 != c3 : " << (c1 != c3) << endl; 30 c4 = c2 + c3; 31 cout << "c4 = c2 + c3, c4 = " << c4 << endl; 32 } 33 34 int main() { 35 test(); 36 }
运行截图:
问题回答:
4. 实验任务4
代码:
Fraction.h
1 #pragma once 2 #include<string> 3 4 class Fraction{ 5 public: 6 static const std::string doc; 7 Fraction(int up=1,int down=1); 8 Fraction(const Fraction &c); 9 10 int get_up()const; 11 int get_down() const ; 12 Fraction negative() const; 13 static int gcd(int a,int b); 14 Fraction simplify()const; 15 16 public: 17 //友元函数 18 friend void output(const Fraction &c); 19 friend Fraction add(const Fraction &c1,const Fraction &c2); 20 friend Fraction sub(const Fraction &c1,const Fraction &c2); 21 friend Fraction mul(const Fraction &c1,const Fraction &c2); 22 friend Fraction div(const Fraction &c1,const Fraction &c2); 23 ~Fraction(); 24 private: 25 int up; 26 int down; 27 28 29 };
Fraction.cpp
1 #include"Fraction.h" 2 #include<iostream> 3 #include<string> 4 #include<cmath> 5 #include <iomanip> 6 7 using std::cout; 8 using std::endl; 9 using std::string; 10 11 12 13 14 const std::string Fraction::doc={"Fraction类v 0.01版.\n目前仅支持分数对象的构造、输出、加/减/乘/除运算.\n"}; 15 Fraction::Fraction(int a,int b):up(a),down{b} {} 16 17 18 Fraction::Fraction(const Fraction &c):up(c.up),down(c.down){ 19 } 20 21 //简化分数 22 Fraction Fraction::simplify()const{ 23 24 int divisor=gcd(up,down); 25 26 return Fraction(up/divisor,down/divisor);} 27 28 29 int Fraction::get_up()const{ 30 Fraction c1=this->simplify(); 31 32 33 return c1.up; 34 } 35 36 37 int Fraction::get_down()const{ 38 Fraction c2=this->simplify(); 39 return c2.down; 40 41 } 42 Fraction Fraction::negative()const { 43 44 return Fraction(-up,down); 45 } 46 47 int Fraction::gcd(int a,int b){ 48 49 while(b!=0){ 50 int temp=b; 51 b=a%b; 52 a=temp; 53 }return a; 54 55 56 } 57 58 59 void output(const Fraction &c){ 60 61 62 if(c.down==0){cout<<"分母不能为0"; return; 63 } 64 if(c.up==0){cout<<0;return;} 65 66 Fraction c1=c.simplify(); 67 if(c1.down==1){cout<<c.up; 68 69 } 70 else{cout<<c1.get_up()<<"/"<<c1.get_down() ; 71 } 72 73 } 74 75 76 77 78 79 80 Fraction add(const Fraction &c1,const Fraction &c2){ 81 82 Fraction c3; 83 c3.up=c1.up*c2.down+c2.up*c1.down; 84 c3.down=c1.down*c2.down; 85 86 return c3.simplify(); 87 88 89 } 90 91 Fraction sub(const Fraction &c1,const Fraction &c2){ 92 Fraction c3; 93 c3.up=c1.up*c2.down-c2.up*c1.down; 94 c3.down=c1.down*c2.down; 95 96 return c3.simplify(); 97 } 98 99 Fraction mul(const Fraction &c1,const Fraction &c2){ 100 Fraction c3; 101 c3.up=c1.up*c2.up; 102 c3.down=c1.down*c2.down; 103 104 return c3.simplify(); 105 } 106 107 108 Fraction div(const Fraction &c1,const Fraction &c2){ 109 Fraction c3; 110 c3.up=c1.up*c2.down; 111 c3.down=c1.down*c2.up; 112 113 return c3.simplify(); 114 } 115 116 Fraction::~Fraction()=default;
Fraction_test.cpp
1 #include "Fraction.h" 2 #include <iostream> 3 4 using std::cout; 5 using std::endl; 6 7 8 void test1() { 9 cout << "Fraction类测试: " << endl; 10 cout << Fraction::doc << endl << endl; 11 12 Fraction f1(5); 13 Fraction f2(3, -4), f3(-18, 12); 14 Fraction f4(f3); 15 cout << "f1 = "; output(f1); cout << endl; 16 cout << "f2 = "; output(f2); cout << endl; 17 cout << "f3 = "; output(f3); cout << endl; 18 cout << "f4 = "; output(f4); cout << endl; 19 20 Fraction f5(f4.negative()); 21 cout << "f5 = "; output(f5); cout << endl; 22 cout << "f5.get_up() = " << f5.get_up() << ", f5.get_down() = " << f5.get_down() << endl; 23 24 cout << "f1 + f2 = "; output(add(f1, f2)); cout << endl; 25 cout << "f1 - f2 = "; output(sub(f1, f2)); cout << endl; 26 cout << "f1 * f2 = "; output(mul(f1, f2)); cout << endl; 27 cout << "f1 / f2 = "; output(div(f1, f2)); cout << endl; 28 cout << "f4 + f5 = "; output(add(f4, f5)); cout << endl; 29 } 30 31 void test2() { 32 Fraction f6(42, 55), f7(0, 3); 33 cout << "f6 = "; output(f6); cout << endl; 34 cout << "f7 = "; output(f7); cout << endl; 35 cout << "f6 / f7 = "; output(div(f6, f7)); cout << endl; 36 } 37 38 int main() { 39 cout << "测试1: Fraction类基础功能测试\n"; 40 test1(); 41 42 cout << "\n测试2: 分母为0测试: \n"; 43 test2(); 44 }
运行截图:
5. 实验任务5
代码:
Bank.h
1 #ifndef ACCOUNT_H 2 #define ACCOUNT_H 3 4 class SavingsAccount{ 5 private://用户的Id ,平均数,利率,上次存款时间,计算,总和这些数是私有的。 6 int id; 7 double balance; 8 double rate; 9 int lastDate; 10 double accumulation; 11 static double total; 12 void record(int data,double amount);//一个成员函数:用于输出 13 double accumulate(int date)const{return accumulation+balance*(date-lastDate);} 14 public: 15 SavingsAccount(int date,int id,double rate); 16 int getId()const{return id; } 17 double getBalance ()const {return balance;} 18 double getRate()const{return rate;} 19 static double getTotal(){return total; 20 } 21 void deposit(int date,double amount);//存 22 void withdraw(int date,double amount);//取 23 void settle(int date);//结算 24 void show()const; 25 }; 26 #endif
Bank.cpp
1 #include <iostream> 2 #include "bank.h" 3 #include <cmath> 4 5 using namespace std; 6 7 double SavingsAccount::total = 0; 8 9 SavingsAccount::SavingsAccount(int date, int id, double rate): id(id), balance(0), rate(rate), lastDate(date), accumulation(0) { 10 std::cout << date << "\t#" << id << " is created" << std::endl; 11 } 12 void SavingsAccount::record(int date, double amount) { 13 accumulation = accumulate(date); 14 lastDate = date; 15 amount = floor(amount * 100 + 0.5) / 100; //保留小数点后两位 16 balance += amount; 17 total += amount; 18 std::cout << date << "\t#" << id << "\t" << amount << "\t"<< balance << std::endl; 19 } 20 void SavingsAccount::deposit(int date, double amount) { 21 record(date, amount); 22 } 23 void SavingsAccount::withdraw(int date, double amount) { 24 if (amount > getBalance()) { 25 std::cout << "Error: not enough money" << std::endl; 26 } 27 else { 28 record(date, -amount); 29 } 30 } 31 void SavingsAccount::settle(int date) { 32 double interest = accumulate(date) * rate / 365; //计算年息 33 if (interest != 0) 34 record(date, interest); 35 accumulation = 0; 36 } 37 void SavingsAccount::show() const { 38 std::cout << "#" << id << "\tBalance: " << balance; 39 }
Bank_test.cpp
1 #include "bank.h" 2 #include <iostream> 3 using namespace std; 4 int main() { 5 6 SavingsAccount sa0(1, 21325302, 0.015); 7 SavingsAccount sal(1, 58320212, 0.015); 8 9 sa0.deposit(5, 5000); 10 sal.deposit(25, 10000); 11 sa0.deposit(45, 5500); 12 sal.withdraw(60, 4000); 13 14 sa0.settle(90); 15 sal.settle(90); 16 17 sa0.show(); 18 cout << endl; 19 sal.show(); 20 cout << endl; 21 cout << "Total: " << SavingsAccount::getTotal() << endl; 22 return 0; 23 }
运行截图:
个人银行账户管理系统使用了SavingsAccout()类封装了相关类的属性以及方法。也有不到位的地方,比如输入日期,钱数,取款数这些数据,要设置确保数据的输入是合理的,部分不能为负数。