提示:这是面向对象设计的第二部分,第一部分点这里
目录
前言
第一部分主要是面向对象设计的大致逻辑以及语法细节,然而本篇博客,同样来自于课堂内容,而课堂内容以实战为主,老师现场从零开始编写了图书馆借阅系统,受益良多。
本篇知识内容较少,侧重于实际项目,或者说样例。
一、案例1:堆栈类
设计一个整型堆栈(Stack)类,要求实现
- 压入一个整数进栈:Push(e)
- 弹出栈顶的整数:Pop()
- 读栈顶的整数值:ReadTop()
- 判断栈是否为空:IsEmpty()
编写main函数,测试堆栈类的正确性
- 创建一个堆栈对象t1,依次压入整数13,-24,76
- 输出t1栈顶的整数值,并输出栈是否为空
- 依据t1创建另外一个栈t2
- 从t2中连续4次弹出栈顶整数,并依次输出弹出的整数
- 输出栈顶的整数值,并输出栈是否为空
1. stack.h头文件
按照上述要求,可以设置头文件如下:
#ifndef __STACK_H
#define __STACK_H
class Stack
{
public:
Stack(int size);
Stack(const Stack& stack);
~Stack();
void Push(int e);
int Pop();
int ReadTop();
bool IsEmpty();
private:
int* m_data;
int m_size;
int m_top;
};
#endif
2. stack.cpp文件
定义stack对象的成员函数
#include "stack.h"
#include <iostream>
using namespace std;
Stack::Stack(int size)
{
m_data = new int[size];
m_size = size;
m_top = -1;
}
Stack::Stack(const Stack& stack)
{
m_size = stack.m_size;
m_top = stack.m_top;
m_data = new int[m_size];
for (int i = 0; i <= m_top; i++)
m_data[i] = stack.m_data[i];
}
Stack::~Stack()
{
delete[] m_data;
}
void Stack::Push(int e)
{
if (m_top >= m_size - 1)
{
cout << "栈已满,无法压栈" << endl;
}
else
{
m_data[++m_top] = e;
}
}
int Stack::Pop()
{
if (m_top >= 0)
{
m_top--;
return m_data[m_top + 1];
}
else
{
cout << "栈已空,无法弹栈" << endl;
return -1;
}
}
int Stack::ReadTop()
{
if (m_top >= 0)
return m_data[m_top];
else
{
cout << "栈为空,无法读栈顶元素" << endl;
return -1;
}
}
bool Stack::IsEmpty()
{
return m_top == -1;
}
二、面向对象编程进一步说明
1. 类的定义与实现
类的定义和实现一般放在不同的文件中
- 类的定义一般放在一个头文件(Reader.h)中,供其它需要使用该类的文件包含
- 类的实现一般放在一个源文件(Reader.cpp)中,该文件需要包含定义该类的头文件
- 类的定义和实现可以放在一个文件里,但不提倡,因为结构不清晰
2. 数据成员与成员函数
- 定义类时不能对数据成员进行初始化,数据成员的初始化放在构造函数中
- 类的成员函数的实现可以写在类里面,也可以写在外面
- 为使程序结构更加清晰,除极短的函数外,建议成员函数的实现都放在源文件中
3. 项目源程序之间的关系
4. 访问控制
为实现信息隐藏和最低访问权原则:
- 如果外部函数不需要访问某些数据,则不给它访问的权限
- 如果外部函数只需要读某些数据,则只给它读的权限
- 如果外部函数需要修改数据才给它全部的访问权限。即使如此,也应通过公有函数接口对私有数据进行修改
- 如果只有少数外部函数和类需要修改数据,则将其设为友元函数和类
5. 静态成员
类的静态成员可以被该类的所有对象共享,包括静态数据成员和静态成员函数
- 静态成员申明以关键字static开始,如: static int objNum;
- 静态数据成员需要在定义类的时候就初始化,但不能在类里面初始化,只能在类外面初始化 int Reader::objNum = 0;
- 静态成员的访问除了可以像普通成员通过对象访问之外,还可以通过类名加作用域运算符直接访问,如 Reader::objNum = 5;
- 静态成员函数只能访问静态数据成员和静态成员函数,但非静态成员函数可以访问静态和非静态成员
6. 预处理指令
使用预处理指令防止头文件被源文件多次包含
#ifndef __BOOK_H //预处理指令
#define __BOOK_H
class Book{
...
};
#endif
7. 构造函数
构造函数重载:重载构造函数以根据不同需要选择不同的对象初始化方法
默认构造函数:调用时不必提供参数的构造函数是默认构造函数,每个类只能有一个默认构造函数
复制构造函数:根据类的某个对象复制出一个完全相同的新的对象的构造函数
- 若不写复制构造函数,系统会自动生成一个复制构造函数,里面是对所有成员进行简单赋值
- 若成员变量含有指针,且要动态分配内存,需要自己重写赋值构造函数,否则很容易出错
#ifndef __BOOK_H
#define __BOOK_H
class Book{
private:
int m_id;
char m_name[100];
bool m_state;
public:
Book(); //默认构造函数
Book(const Book& book); //复制构造函数
Book(int id, char* name);
//构造函数重载
};
#endif
//复制构造函数
#ifndef __STACK_H
#define __STACK_H
class Stack{
private:
int* m_data;
public:
Stack();
Stack(const Stack& stack);
};
#endif
三、案例2:图书管理系统
编写图书管理系统, 该系统可以
- 添加图书、删除图书、打印所有的图书、打印未借出的图书、打印已借出的图书
- 添加读者、删除读者、打印所有的读者信息
- 借书、还书、显示借书列表
编写main函数,测试系统正确性
- 添加4本图书、2个读者
- 打印所有的图书和所有的读者
- 删除第3本图书,然后打印所有未借出的图书
- 读者1借剩下的第3本书,读者2借剩下的第1本书
- 打印所有的图书信息
1. 系统设计
2. 代码设计
(1)Book类
头文件
#ifndef __BOOK_H
#define __BOOK_H
class Reader;
class Book
{
private:
long m_id; // 图书ID
char m_name[30]; // 图书名称
bool m_state; // 图书状态,false表示未借出,true表示已借出
Reader* m_keeper; // 借阅人
public:
// 构造函数
Book(long id, char name[]);
// 析构函数
~Book(){}
// 打印书籍信息
void ShowInfo();
// 设置图书状态
void SetState(bool state);
// 获取图书状态
bool GetState();
// 设置借阅人
void SetKeeper(Reader* r);
// 获取书籍id
long GetId();
};
#endif
源文件
#include "book.h"
#include "reader.h"
#include <iostream>
using namespace std;
// 构造函数
Book::Book(long id, char name[])
{
m_id = id;
strcpy(m_name, name);
m_state = false;
m_keeper = NULL;
}
// 打印书籍信息
void Book::ShowInfo()
{
cout << m_id << " " << m_name << " ";
cout << (m_state ? "借出" : "未借出") << " ";
if (m_keeper != NULL)
cout << m_keeper->GetName();
cout << endl;
}
// 设置图书状态
void Book::SetState(bool state)
{
m_state = state;
}
// 获取图书状态
bool Book::GetState()
{
return m_state;
}
// 设置借阅人
void Book::SetKeeper(Reader* r)
{
m_keeper = r;
}
// 获取书籍id
long Book::GetId()
{
return m_id;
}
(2)Reader类
头文件
#ifndef __READER_H
#define __READER_H
class Book;
class Reader
{
private:
long m_id; // 读者id
char m_name[30]; // 读者姓名
int m_brrBookNum; // 借书数量
Book* m_brrBooks[10]; // 借书列表
public:
// 构造函数
Reader(long id, char name[]);
// 析构函数
~Reader() {}
// 打印读者信息
void ShowInfo();
// 获取读者姓名
char* GetName();
// 借书,若借书失败,返回false
bool BorrowBook(Book* b);
// 还书,若还书失败,返回false
bool ReturnBook(Book* b);
// 显示借阅书籍
void ShowBrrBooks();
// 获取读者id
long GetId();
// 是否有借书
bool HasBrrBooks();
};
#endif
源文件
#include "reader.h"
#include "book.h"
#include <string.h>
#include <iostream>
using namespace std;
// 构造函数
Reader::Reader(long id, char name[])
{
m_id = id;
strcpy(m_name, name);
m_brrBookNum = 0;
for (int i = 0; i < 10; i++)
m_brrBooks[i] = NULL;
}
// 打印读者信息
void Reader::ShowInfo()
{
cout << m_id << "\t" << m_name << "\t" << m_brrBookNum << endl;
}
// 获取读者姓名
char* Reader::GetName()
{
return m_name;
}
// 借书,若借书失败,返回false
bool Reader::BorrowBook(Book* b)
{
if (m_brrBookNum < 10)
{
m_brrBooks[m_brrBookNum++] = b;
return true;
}
else
{
cout << "借书已满,借书失败" << endl;
return false;
}
}
// 还书,若还书失败,返回false
bool Reader::ReturnBook(Book* b)
{
for (int i = 0; i < m_brrBookNum; i++)
{
if (m_brrBooks[i] == b)
{
m_brrBooks[i] = m_brrBooks[m_brrBookNum - 1];
m_brrBooks[m_brrBookNum - 1] = NULL;
m_brrBookNum--;
return true;
}
}
cout << "该图书不在当前读者的借阅书籍列表中,还书失败" << endl;
return false;
}
// 显示借阅书籍
void Reader::ShowBrrBooks()
{
for (int i = 0; i < m_brrBookNum; i++)
{
m_brrBooks[i]->ShowInfo();
}
}
// 获取读者id
long Reader::GetId()
{
return m_id;
}
// 是否有借书
bool Reader::HasBrrBooks()
{
return m_brrBookNum > 0;
}
(3)Manager类
头文件
#ifndef __MANAGER_H
#define __MANAGER_H
#define MAX_READER_NUM 1000
#define MAX_BOOK_NUM 1000
class Reader;
class Book;
class Manager
{
private:
Book* m_bookList[MAX_BOOK_NUM]; // 书籍列表
int m_bookNum; // 书籍数量
Reader* m_readerList[MAX_READER_NUM]; // 读者列表
int m_readerNum; // 读者数量
public:
// 构造函数
Manager();
// 析构函数
~Manager();
// 运行系统
void Run();
// 显示操作信息
void ShowScreenInfo();
// 添加图书
void AddBook();
// 删除图书
void DeleteBook();
// 打印所有图书
void PrintAllBooks();
// 添加读者
void AddReader();
// 删除读者
void DeleteReader();
// 打印所有读者
void PrintAllReaders();
// 借书
void BorrowBook();
// 还书
void ReturnBook();
};
#endif
源文件
#include "manager.h"
#include "book.h"
#include "reader.h"
#include <iostream>
using namespace std;
int book_id = 1000;
int reader_id = 2000;
// 构造函数
Manager::Manager()
{
m_bookNum = 0;
for (int i = 0; i < MAX_BOOK_NUM; i++)
m_bookList[i] = NULL;
m_readerNum = 0;
for (i = 0; i < MAX_READER_NUM; i++)
m_readerList[i] = NULL;
}
// 析构函数
Manager::~Manager()
{
for (int i = 0; i < m_bookNum; i++)
delete m_bookList[i];
for (i = 0; i < m_readerNum; i++)
delete m_readerList[i];
}
// 添加图书
void Manager::AddBook()
{
cout << "请输入书籍名称:";
char name[30];
cin >> name;
long id = ++book_id;
Book* pbook = new Book(id, name);
m_bookList[m_bookNum++] = pbook;
}
// 删除图书
void Manager::DeleteBook()
{
cout << "请输入要删除的图书ID: ";
int id;
cin >> id;
for (int i = 0; i < m_bookNum; i++)
{
if (m_bookList[i]->GetId() == id)
{
if (m_bookList[i]->GetState() == true)
{
cout << "书籍已借出,请还书后再删除" << endl;
}
else
{
delete m_bookList[i];
for (int j = i; j < m_bookNum - 1; j++)
m_bookList[j] = m_bookList[j + 1];
m_bookNum--;
}
break;
}
}
}
// 打印所有图书
void Manager::PrintAllBooks()
{
for (int i = 0; i < m_bookNum; i++)
{
m_bookList[i]->ShowInfo();
}
}
// 添加读者
void Manager::AddReader()
{
cout << "请输入读者姓名:";
char name[30];
cin >> name;
long id = ++reader_id;
Reader* preader = new Reader(id, name);
m_readerList[m_readerNum++] = preader;
}
// 删除读者
void Manager::DeleteReader()
{
cout << "请输入要删除的读者ID: ";
int id;
cin >> id;
for (int i = 0; i < m_readerNum; i++)
{
if (m_readerList[i]->GetId() == id)
{
if (m_readerList[i]->HasBrrBooks())
{
cout << "该读者有借书,请还书后再删除" << endl;
}
else
{
delete m_readerList[i];
for (int j = i; j < m_readerNum - 1; j++)
m_readerList[j] = m_readerList[j + 1];
m_readerNum--;
}
break;
}
}
}
// 打印所有读者
void Manager::PrintAllReaders()
{
for (int i = 0; i < m_readerNum; i++)
{
m_readerList[i]->ShowInfo();
}
}
// 借书
void Manager::BorrowBook()
{
cout << "请输入借阅人id: ";
int rId;
cin >> rId;
cout << "请输入书籍id: ";
int bId;
cin >> bId;
Book* b = NULL;
for (int i = 0; i < m_bookNum; i++)
{
if (m_bookList[i]->GetId() == bId)
b = m_bookList[i];
}
Reader* r = NULL;
for (i = 0; i < m_readerNum; i++)
{
if (m_readerList[i]->GetId() == rId)
r = m_readerList[i];
}
if(r->BorrowBook(b) == true)
{
b->SetState(true);
b->SetKeeper(r);
}
}
// 还书
void Manager::ReturnBook()
{
}
// 显示操作信息
void Manager::ShowScreenInfo()
{
cout << "=================" << endl;
cout << "1: 添加图书" << endl;
cout << "2: 删除图书" << endl;
cout << "3: 打印图书" << endl;
cout << "4: 添加读者" << endl;
cout << "5: 删除读者" << endl;
cout << "6: 打印读者" << endl;
cout << "7: 借书" << endl;
cout << "8: 还书" << endl;
cout << "=================" << endl;
}
// 运行系统
void Manager::Run()
{
while(1)
{
system("cls");
ShowScreenInfo();
cout << "请选择对应的操作:";
int op;
cin >> op;
switch(op)
{
case 1:
AddBook();
break;
case 2:
DeleteBook();
break;
case 3:
PrintAllBooks();
break;
case 4:
AddReader();
break;
case 5:
DeleteReader();
break;
case 6:
PrintAllReaders();
break;
case 7:
BorrowBook();
break;
case 8:
ReturnBook();
break;
default:
break;
}
cout << "请按任意键继续操作" << endl;
char c;
cin >> c;
}
}
(4) main 源文件
#include "manager.h"
int main()
{
Manager mgr;
mgr.Run();
return 0;
}
总结
还是要动手实操,自己尝试面向对象编写项目,才能更好的掌握面向对象编程的能力。