java转c++的第三天,写完了人生中的第一个c++小程序,啥也不说了,直接贴源码:
注释里面是我写的时候的一些思考和写完之后的经验教训,给自己和其他初学c++的猿友们加油!
//教训: //①(已改进!)代码复用度不够高,可以多新建几个局部函数(尤其是查找函数),或者是把这些函数添加进类里, //就像Java一样,面向对象编程 //②(未改进!)用结构体来实现结点会好一些。 //③注意new (在堆区)和直接定义类(局部函数在栈上)的区别 //④区别指针和应用和对象本体的区别,特别是要注意有些不应该更改形参的地方,应该使用引用或者是const。 //⑤注意删除的时候一定要先令temp_2 =temp_1,temp_1 = temp_nextNode,最后再delete temp_2.否则会出现逻辑错误。 //⑥注意使用对象时用“.”使用对象的指针时用“->” //⑦该通信录没有加入去重功能
需要源码的人直接从下面开始粘贴就好,把源码粘贴到编译器里就方面阅读了,第一次写博客,嫌麻烦,不想排版了。
#include<iostream> #include <vector>
using namespace std; //联系人链表 //使用类而不是结构体 class Person { //默认是private权限,为了使外部程序可以访问应该写成public权限 public: string name; public: string sex; public: int age; public: string num; public: string addr;
//运算符重载,判断两个person对象是否相等 bool operator==(Person &a)//注意这里面使用引用比使用指针好,不会修改数据, { if (this->name == a.name && this->sex == a.sex && this->age == a.age && this->num == a.num && this->addr == a.addr) return true; else return false; }
//修改函数 public: void revise() { cout << "请输入联系人姓名:" << endl; cin >> this->name; cout << "请输入联系人性别:" << endl; cin >> this->sex; cout << "请输入联系人年龄:" << endl; cin >> this->age; cout << "请输入联系人电话号码:" << endl; cin >> this->num; cout << "请输入联系人地址:" << endl; cin >> this->addr; } //构造函数1 public: Person(string name, string sex, int age, string num, string addr) :name(name), sex(sex), age(age), num(num), addr(addr) { cout << "成功新建联系人"<<name<<"!" << endl; } //构造函数2 public: Person(){} //析构函数 public: ~Person() { ; } }; class PersonList { //注意这里一定要写成public,不然下一个结点新建或者删除时,无法修改这些数据 //说明链表的结点还是用结构体会好一些 public: Person* val;//注意这里只是一个指针 public: PersonList* nextNode;//指向下一个结点的指针 public: PersonList* beforeNode;
//遍历到当前链表的最后一个节点 public: PersonList* toEnd()//返回指向最后一个节点的指针 { PersonList* res = this; //cout << this; //cout << this->beforeNode; while (res->nextNode != NULL) { res = res->nextNode; } //cout << res; return res; } public:PersonList(Person* val, PersonList* beforeNode) { this->val = val; this->beforeNode = beforeNode; //cout << "当前的list" << this << endl; if (beforeNode) { //cout << "已经在前一个结点添加指向该节点的指针" << endl; beforeNode->nextNode = this;//让前一个节点的下一个节点指向当前的这个节点 //cout << "当前的list" << this << endl; //cout << "beforeNode的nextNode"<< beforeNode->nextNode << endl; //cout << "beforeNode的地址" << beforeNode << endl; }
this->nextNode = NULL;
} public:~PersonList() { //析构函数要完成:1.删除val指针指向的Person类 2.使上一个节点的nextNode指向当前nextNode //3.使下一个节点指向的beforeNode指向当前的beforeNode
delete this->val;//!!!万分注意,这里里面的delete要应用于一个指针。不然就会报错! //因为第一个节点的beforeNode是head,所以无需要考虑上一个节点是否为空 (this->beforeNode)->nextNode = this->nextNode; if((this->nextNode) != NULL) (this->nextNode)->beforeNode = this->beforeNode; //test //cout << "调用了PersonList的析构函数" << endl;
} };
//显示菜单 void showMenu() { cout << "***************************" << endl; cout << "***** 1、添加联系人 *****" << endl; cout << "***** 2、显示联系人 *****" << endl; cout << "***** 3、删除联系人 *****" << endl; cout << "***** 4、查找联系人 *****" << endl; cout << "***** 5、修改联系人 *****" << endl; cout << "***** 6、清空联系人 *****" << endl; cout << "***** 0、退出通讯录 *****" << endl; cout << "***************************" << endl;
}
//添加联系人 void addContact(PersonList* head) {
Person* ptr_person = new Person; //调用person类的修改函数来添加 ptr_person->revise(); //一定要用new,不然会在局部函数结束后自动析构掉局部函数创建的变量,因为直接 //定义的话,该对象是在栈里新建的,局部函数执行完成之后,栈会自动弹出 //如果是new,就是在堆区新建,不会自动析构 new PersonList (ptr_person, head->toEnd());
cout << "将联系人"<< ptr_person ->name<<"成功添加到通信录!" << endl; };
//显示联系人 void showContacts(PersonList* head) { if (head->nextNode == NULL) { cout << "当前通信录为空" << endl; return; } PersonList* temp = head->nextNode; cout << "通信录所有内容如下:" << endl; while (temp != NULL) { cout << temp->val->name << " " << temp->val->sex << " " << temp->val->age << " " << temp->val->num << " " << temp->val->addr << endl; temp = temp->nextNode; } }
//查找联系人,注意应该先定义查找,这样才能方便在删除函数中使用查找函数 void searchContacts(PersonList* head) { if (head->nextNode == NULL) { cout << "当前通讯录为空!" << endl; return; }
Person person; vector<PersonList*> arr;//定义一个容器数组arr PersonList* temp = head->nextNode;//用temp来遍历数组 cout << "请输入待查找联系人的姓名:" << endl; cin >> person.name;
while (temp != NULL) { if (temp->val->name == person.name) arr.push_back(temp);//向vector末尾添加元素 temp = temp->nextNode; }
//通过vector的大小来确定下一步操作 if(arr.size() == 0) { cout << "当前通讯录无此人!" << endl; return; } else { cout << "查找到:" << endl; for (int i = 0; i < arr.size(); i++) { cout << arr[i]->val->name << " " << arr[i]->val->sex << " " << arr[i]->val->age << " " << arr[i]->val->num << " " << arr[i]->val->addr << endl; } } }
//删除联系人(在查找联系人基础上修改) void deleteContact( PersonList* head) { if (head->nextNode == NULL) { cout << "当前通讯录为空!" << endl; return; }
//删除联系人首先用名字寻找,如果遇到同名的,就要求用户输入更多详细信息 Person person; vector<PersonList*> arr;//定义一个容器数组arr PersonList* temp = head->nextNode;//用temp来遍历数组 cout << "请输入待删除联系人的姓名:" << endl; cin >> person.name;
while (temp != NULL) { if (temp->val->name == person.name) arr.push_back(temp);//向vector末尾添加元素 temp = temp->nextNode; }
//通过vector的大小来确定下一步操作 switch (arr.size()) { case 0: cout << "当前通讯录无此人!" << endl; return; case 1: delete arr[0];//delete会调用析构函数 cout << "删除联系人" << person.name << "成功" << endl; return; default: cout << "存在" << arr.size() << "个同名联系人!输入0取消删除,输入1删除全部,输入2进行精确删除" << endl; break; }
//此时说明存在同名联系人 int flag = 0;//标记删除了几个联系人 int r;//标记下一步动作 cin >> r; switch (r) { case 1: for (int i = 0; i < arr.size(); i++) delete arr[i]; cout << "已经删除" << arr. size()<< "个联系人!" << endl; break; case 2: cout << "请输入该联系人性别:" << endl; cin >> person.sex; cout << "请输入该联系人年龄:" << endl; cin >> person.age; cout << "请输入该联系人电话号码:" << endl; cin >> person.num; cout << "请输入该联系人地址:" << endl; cin >> person.addr;
//这里要判断对象是否相等,使用运算符重载对两个对象进行直接判断 for (int i = 0; i < arr.size(); i++) { if ((*arr[i]->val) == person)//由此可以看出解指针的优先级更低一些 { delete arr[i]; flag++; } } cout << "已经删除" << flag << "个联系人!" << endl; break; default: cout << "已经取消删除" << endl; return; }
}
//修改联系人(在删除函数基础上修改)) void reviseContacts(PersonList* head){ if (head->nextNode == NULL) { cout << "当前通讯录为空!" << endl; return; }
if (head->nextNode == NULL) { cout << "当前通讯录为空!" << endl; return; }
//删除联系人首先用名字寻找,如果遇到同名的,就要求用户输入更多详细信息 Person person; vector<PersonList*> arr;//定义一个容器数组arr PersonList* temp = head->nextNode;//用temp来遍历数组 cout << "请输入待修改联系人的姓名:" << endl; cin >> person.name;
while (temp != NULL) { if (temp->val->name == person.name) arr.push_back(temp);//向vector末尾添加元素 temp = temp->nextNode; }
//通过vector的大小来确定下一步操作 switch (arr.size()) { case 0: cout << "当前通讯录无此人!" << endl; return; case 1: arr[0]->val->revise();//调用revise函数,复用代码 cout << "修改联系人" << person.name << "成功" << endl; return; default: cout << "存在" << arr.size() << "个同名联系人!请输入详细信息以确定修改哪一位联系人" << endl; person.revise(); for (int i = 0; i < arr.size(); i++) { if ((*arr[i]->val) == person) { arr[i]->val->revise();//调用第一个符合条件的联系人的修改函数,只修改第一个! //从这里还能看出面向对象的好处 cout << "修改联系人"<<person.name<<"成功!" << endl; return; } } cout << "无符合条件的联系人!" << endl; break; }
}
//删除所有联系人 void deleteAllContacts(PersonList* head) { PersonList* temp_1 = head->nextNode; PersonList* temp_2 = NULL;//防止temp_2在通信录为空时,得不到初始化的问题。 while (temp_1 != NULL) { temp_2 = temp_1; temp_1 = temp_1->nextNode; delete temp_2; }
if (head->nextNode == NULL) cout << "已清空通讯录!" << endl; } //main函数 int main() { //test /*int a = 10; int* ptr_a = &a; int* ptr_b = ptr_a; cout << *ptr_a << endl << *ptr_b;*/ //首先新建一个联系人链表的头 PersonList* head = new PersonList(NULL, NULL); int select = 0;
while (true) { //显示菜单 showMenu(); //获取选项 cin >> select; //根据选项进行操作 switch (select) { case 1: addContact(head); break; case 2: showContacts(head); break; case 3:deleteContact(head); break; case 4:searchContacts(head); break; case 5:reviseContacts(head); break; case 6:deleteAllContacts(head); break; case 0: return 0; default: break; }
//
}
}
