好久沒用C++了,正好同學有個面試題,於是就幫忙看了一下.雖然對C++的知識瞭解不少, 但是長期被Java浸淫, 發現這個簡單的程序卻也寫着也不是那麼順手.好在最後還是搞定了,下面分析一下,題目如下, 小弟不才, 可能有錯誤的地方 ,還請大神指正
把這個題目分成了Group, User ,WechatServer三個類, 具體就是一點簡單的操作, 後面將附上源碼.這裏記錄一下自己寫時候遇到問題的一些總結:
1.實現單例, 這和Java差距還是有些的. WechatServer需要一個單例, 這樣可以保持User列表,和group列表,
代碼實現如下:
class WechatServer{
private:
WechatServer(){}
static WechatServer* m_Instance;
vector<User*> mUsers;
vector<Group*> mGroups;
public:
//need use singleton
static WechatServer* GetInstance()//這裏使用了餓漢式
{
if(!m_Instance)
m_Instance = new WechatServer();
return m_Instance;
}
User* findUserById(int id); //這些函數在WechatServer.cpp中實現, 當然其實可以在任何一個include了WechatServer.h的cpp文件中實現 .cpp文件不過是爲了讓代碼更加模塊化
vector<User*> getUsers();
void createGroup(vector<User*> users , int creatorId);
void addUser(User* user);
};
2.互相include問題, 這裏遇到兩個問題
A 重複編譯問題, 編譯的時候, User 和 Group互相include了, 開始的時候,發現編譯器編譯到這裏死循環了,也好理解
編譯Group的時候由於include了User就去先編譯User,但是編譯User的時候有發現include了Group也是去編譯Group…
解決方案當然很簡單. 參考 http://yuanzhifei89.iteye.com/blog/2020082
把代碼放到下面的代碼塊中:
#ifndef _Group_H
#define _Group_H
//防止嵌套include導致編譯死循環
#endif
B 這時候編譯Group的時候發現找不到User類了, 原因先編譯Group的時候,User類沒有編譯處理, 所以做了一個前置聲明解決問題
整體代碼
#ifndef _Group_H
#define _Group_H
//防止嵌套include導致編譯死循環
#include <iostream>
#include <vector>
//#include "User.h"
using namespace std;
class User;//這裏是C++類的前向聲明,沒有用include“User.h”
//編譯到一塊之後User*自然指向了User class
//其實很簡單, 是先編譯了Group又編譯了User, 最後編譯了WechatServer, 按照字母順序
//所以User也可以前向聲明一個class WechatServer
class Group{
public:
int mGroupId,mCreatorId;
vector<User*> mMembers;
Group(int groupId , int creatorId){
mGroupId = groupId;
mCreatorId = creatorId;
}
void addMembers(vector<User*> users){
for (vector<User*>::size_type i = 0; i != users.size(); ++i)
{
mMembers.push_back(users[i]);
}
}
};
#endif
3. C++特有符號
符號:: 可以認爲限定搜索範圍, 如果想在User.cpp中實現User.h中聲明的getId()函數,或者使用User.h聲明的mFriends私有成員變量必須這麼寫: 沒有User::會報錯.同時, 其實在main.cpp中實現這個函數也沒有任何問題 .h真正包含了類,cpp不過是 他們的實現而已, 裏面的內容可以寫在任何地方
User.h:
int mWeChatId;
User.cpp:
int User::getId(){return User::mWechatId}
符號”.” : 這是C++的對象調用函數使用的, 也說明類不過是struct的延伸
符號 -> : 指針調用函數使用
& 和 * : 地址和指針
&作用在一個對象和基本類型簽名, 是取這個對象/類型的地址, 其實這個地址就是指針用到的, 所以可以給指針賦值:
User user;//真正賦值到內存了
user.getId();
User* uptr = &user;//地址就是指針
uptr->getId();
另外&用在函數中還有傳遞引用的左右,
int p = 8;
test(int &i){
i = 88;
}
test(p);// p = 88
4.堆和棧
在這個問題中new了八個User, 開始把User放到了棧中, 結果他們的地址都是一個.後來放到堆中解決.
//User user(1000 + i, 84508241+ i , phone , email);
//cout<<&user; 這樣放到了棧中, 這裏雖然循環了八次, 但是打印出來的地址其實都是同一個
//需要把user放到堆中, 這樣纔可以生成八個User
User* user = new User(1000 + i, 84508241+ i , phone , email);
cout << user;
wechatServer->addUser(user);
5.vector的遍歷
void addFreind(User* user ,vector<User*> userlist){
int friendCount = 0;
for (vector<User*>::size_type i = 0; i != userlist.size(); ++i)
{
User* myfriend = userlist[i];
//can not add myself
if(myfriend->getId() != user->getId() && friendCount < 5){
cout << "adding friend : "<< myfriend->getId()<<endl;
user->addFriend(myfriend);
friendCount ++;
}
}
}
6.const
類似java中的final, 不可變
參考http://cnmtjp.blog.51cto.com/204390/35976
void f(const int i) { .........}
//對傳入的參數進行類型檢查,不匹配進行提示
void f(const int i) { i=10;//error! }
//如果在函數體內修改了i,編譯器就會報錯
const 函數
修飾類成員函數
void func() const; // const成員函數中不允許對數據成員進行修改,如果修改,編譯器將報錯。如果某成員函數不需要對數據成員進行修改,最好將其聲明爲const 成員函數,這將大大提高程序的健壯性。
const 爲函數重載提供了一個參考
class A
{
public:
void func(); // [1]:一個函數
void func() const; // [2]:上一個函數[1]的重載
……
};
A a(10);
a.func(); // 調用函數[1]
const A b(100); //const的變量調用const的函數
b.func(); // 調用函數[2]
項目git地址 https://git.oschina.net/sfshine/CppDemoWechat.git
IDE :QTCreator 2.4.1