360笔试题两则
记忆深刻的两道题:
1.如下程序的输出是什么:
#include <stdio.h> class Base { public: Base(){printf("BaseContor\n");foo();} ~Base(){printf("BaseDeContor\n");foo();} virtual void foo(){printf("Base foo\n");} }; class Derive:public Base { public: Derive(){printf("DeriveContor\n");foo();} ~Derive(){printf("DeriveDeContor\n");foo();} virtual void foo(){printf("Derive foo\n");} }; int main() { Base* b=new Derive(); delete b; return 0; }
解释一下:基类指针指向子类对象,C++按照先基类后子类的方式创建对象,在构造基类对象的过程中调用基类构造方法,这个时候虚函数表还没有被子类虚函数指针替换,调用的还是基类对象的函数。于是输出两个Base。之后输出两个子类对象调用的方法。析构的时候由于基类对象的构造函数没有声明为虚函数(见effective C++ item37),所以当基类指针指向子类对象的时候,释放这个基类指针就会调用基类的析构函数而不会调用子类的析构函数,C++把这个对象当做了基类来处理,虚机制没有派上用场,最后输出两个Base。如果在Base的析构函数前加上virtual关键字,那么输出如下:
析构的时候会先调用子类的析构函数进行析构,析构之后再调用基类的析构函数析构,这个时候C++把这个半没析构半被析构的对象当做基类来看待,所以其虚机制也就作废了,因此调用到的还是基类的Base foo。
根据effective C++ item9 的说法,不要在任何构造函数和析构函数中调用虚函数,这样会引起非预期的输出,详见http://www.soft6.com/tech/13/135076.html
引用其中最重要的一段话:
“事实上还有比这更具基本的要求。在派生类对象的基类对象构造过程中,该类的类型是基类类型。不仅虚函数依赖于基类,而且使用运行时刻信息的语言的相应部分(例如,dynamic_cast(参见Item 27)和typeid)也把该对象当基类类型对待。在我们的示例中,当Transaction的构造器正运行以初始化BuyTransaction对象的基类部分时,该对象是Transaction类型。在C++编程中处处都这样处理,这样做很有意义:在基类对象的初始化中,派生类对象BuyTransaction相关部分并未被初始化,所以其时把这些部分当作根本不存在是最安全的。 在一个派生类对象的构造器开始执行之前,它不会成为一个派生类对象的。
在对象的析构期间,存在与上面同样的逻辑。一旦一个派生类的析构器运行起来,该对象的派生类数据成员就被假设为是未定义的值,这样以来,C++就把它们当做是不存在一样。一旦进入到基类的析构器中,该对象即变为一个基类对象,C++中各个部分(虚函数,dynamic_cast运算符等等)都这样处理。”
第二题:
假设有M个传教士和C个野人要过河(M>=C),只有一条船,一次可以载两个人渡河。如果某一边的野人数大于了传教士数,那么传教士会被吃掉。假设野人是听话的,那么请编程找出一种安全的渡河方式,让所有的人都渡过河。(明天再写吧。。祝自己明天早上百度笔试好运,注:最后悲剧了!!!编程之美上的一道原题没有答上来,字符串相似度的那个!!。。。啊啊啊啊)
#include <stdio.h> #include <stack> #include <vector> using namespace std; enum stateKind { NEXT, BACK }; class state { public: static const int NEXTSTATE=3; //三种去的方式 static const int BACKSTATE=5; //五种回来的方式 state(stateKind kind,int localM,int localC,int oppM,int oppC):stateNum(0),backStateNum(0) { localMan=localM; localBeast=localC; oppMan=oppM; oppBeast=oppC; stateKind=kind; } ~state(){}; bool testConflict() { if (localMan<0 || localBeast<0 || oppBeast<0 || oppMan<0) { return true; } if ((localBeast > localMan && localMan>0) || (oppBeast > oppMan && oppMan>0)) { return true; } else { return false; } } bool testEnd() { if (localMan==0 && localBeast==0) { return true; } else { return false; } } state* switchNextState() { if (stateKind == NEXT) { switch (++stateNum) { case 1: printf("在(%d,%d,%d,%d)的情况下尝试让俩野人过河\n",localMan,localBeast,oppMan,oppBeast); return new state(BACK,localMan,localBeast-2,oppMan,oppBeast+2); case 2: printf("在(%d,%d,%d,%d)的情况下尝试让一牧师一野人过河\n",localMan,localBeast,oppMan,oppBeast); return new state(BACK,localMan-1,localBeast-1,oppMan+1,oppBeast+1); case 3: printf("在(%d,%d,%d,%d)的情况下尝试让俩牧师过河\n",localMan,localBeast,oppMan,oppBeast); return new state(BACK,localMan-2,localBeast,oppMan+2,oppBeast); default: return NULL; } } if (stateKind == BACK) { switch (++backStateNum) { case 1: printf("在(%d,%d,%d,%d)的情况下尝试让一个牧师把船划回去\n",localMan,localBeast,oppMan,oppBeast); return new state(NEXT,localMan+1,localBeast,oppMan-1,oppBeast); case 2: printf("在(%d,%d,%d,%d)的情况下尝试让一个野人把船划回去\n",localMan,localBeast,oppMan,oppBeast); return new state(NEXT,localMan,localBeast+1,oppMan,oppBeast-1); case 3: printf("在(%d,%d,%d,%d)的情况下尝试让两个野人把船划回去\n",localMan,localBeast,oppMan,oppBeast); return new state(NEXT,localMan,localBeast+2,oppMan,oppBeast-2); case 4: printf("在(%d,%d,%d,%d)的情况下尝试让两个传教士把船划回去\n",localMan,localBeast,oppMan,oppBeast); return new state(NEXT,localMan+2,localBeast,oppMan-2,oppBeast); case 5: printf("在(%d,%d,%d,%d)的情况下尝试让一个野人和一个传教士把船划回去\n",localMan,localBeast,oppMan,oppBeast); return new state(NEXT,localMan+1,localBeast+1,oppMan-1,oppBeast-1); default: return NULL; } } } int localMan; int localBeast; int oppMan; int oppBeast; int stateNum; int backStateNum; stateKind stateKind; }; bool alreadyPushed(std::vector<state>& alradyPushed,state* nextState) { for (std::vector<state>::iterator it=alradyPushed.begin();it!=alradyPushed.end();it++) { if ((*it).localBeast == nextState->localBeast && (*it).localMan == nextState->localMan && (*it).oppBeast == nextState->oppBeast && (*it).oppMan == nextState->oppMan && (*it).stateKind == nextState->stateKind) { return true; } } return false; } int main() { std::stack<state*> stateStack; std::vector<state> alradyPushed; state* currentState=new state(NEXT,3,3,0,0); state* nextState; if (currentState->testConflict()) { printf("输入就冲突!\n"); } else { stateStack.push(currentState); while (!currentState->testEnd()) { nextState=currentState->switchNextState(); if (NULL == nextState) { printf("在(%d,%d,%d,%d)的状态转换被试完,抛弃此状态\n",currentState->localMan,currentState->localBeast,currentState->oppMan,currentState->oppBeast); currentState=stateStack.top(); stateStack.pop(); delete currentState; if (stateStack.empty()) { printf("根本没办法过河!!!!\n"); break; } currentState=NULL; currentState=stateStack.top(); } else { if (!nextState->testConflict()) { if (!alreadyPushed(alradyPushed,nextState)) { stateStack.push(nextState); alradyPushed.push_back(*nextState); currentState=nextState; } } else { if (stateStack.empty()) { return 0; } printf("在(%d,%d,%d,%d)状态冲突,回退!\n",nextState->localMan,nextState->localBeast,nextState->oppMan,nextState->oppBeast); currentState=stateStack.top(); } } } while(!stateStack.empty()) { currentState=stateStack.top(); printf("牧师=%d,野人=%d |||| 牧师=%d,野人=%d\n",currentState->localMan,currentState->localBeast,currentState->oppMan,currentState->oppBeast); stateStack.pop(); } } return 0; }
深度遍历,弱爆了,其实没有彻底遍历,找到一条可行路线则立马退出,和规则的设置顺序有关系,应该全部遍历然后找最小的那个