项目场景:
在使用C++实现状态模式的例子时,发现出现编译错误,一开始以为是使用了未定义的类导致的,添加了类的声明后发现还是编译失败,很伤心。
问题描述:
首先上图: 然后是源码:
#include <iostream>
#include <memory>
class Work;
class State
{
public:
virtual void WriteProgram(Work* ptrWork) = 0;
};
class ForenoonState;
class Work
{
private:
std::shared_ptr<State> smartState;
double hour;
bool finish;
public:
Work() : hour(0), finish(false), smartState(std::make_shared<ForenoonState>()) {}
void SetHour(const double h)
{
hour = h;
}
double GetHour() const
{
return hour;
}
void SetFinish(bool bFinish)
{
finish = bFinish;
}
bool GetFinish() const
{
return finish;
}
void SetState(std::shared_ptr<State> pState)
{
smartState = pState;
}
std::shared_ptr<State> GetState() const
{
return smartState;
}
void WriteProgram()
{
smartState->WriteProgram(this);
}
};
class SleepingState : public State
{
public:
void WriteProgram(Work* ptrWork)
{
std::cout << "当前时间:" << ptrWork->GetHour() << "点 撑不住了,睡觉吧!" << std::endl;
}
};
class RestState : public State
{
public:
void WriteProgram(Work* ptrWork)
{
std::cout << "当前时间:" << ptrWork->GetHour() << "点 下班回家了!" << std::endl;
}
};
class EveningState : public State
{
public:
void WriteProgram(Work* ptrWork)
{
if (ptrWork->GetFinish())
{
ptrWork->SetState(std::make_shared<RestState>());
ptrWork->WriteProgram();
return;
}
if (ptrWork->GetHour() < 21)
{
std::cout << "当前时间:" << ptrWork->GetHour() << "点 加班吆,疲惫啊!" << std::endl;
}
else
{
ptrWork->SetState(std::make_shared<SleepingState>());
ptrWork->WriteProgram();
}
}
};
class AfternoonState : public State
{
public:
void WriteProgram(Work* ptrWork)
{
if (ptrWork->GetHour() < 17)
{
std::cout << "当前时间:" << ptrWork->GetHour() << "点 下午状态还不错,继续努力!" << std::endl;
}
else
{
ptrWork->SetState(std::make_shared<EveningState>());
ptrWork->WriteProgram();
}
}
};
class NoonState : public State
{
public:
void WriteProgram(Work* ptrWork)
{
if (ptrWork->GetHour() < 13)
{
std::cout << "当前时间:" << ptrWork->GetHour() << "点 饿了,午饭,犯困,午休!" << std::endl;
}
else
{
ptrWork->SetState(std::make_shared<AfternoonState>());
ptrWork->WriteProgram();
}
}
};
class ForenoonState : public State
{
public:
void WriteProgram(Work* ptrWork)
{
if (ptrWork->GetHour() < 12)
{
std::cout << "当前时间:" << ptrWork->GetHour() << "点 上午工作,精神百倍!" << std::endl;
}
else
{
ptrWork->SetState(std::make_shared<NoonState>());
ptrWork->WriteProgram();
}
}
};
int main()
{
std::shared_ptr<Work> work = std::make_shared<Work>();
work->SetHour(9);
work->WriteProgram();
work->SetHour(10);
work->WriteProgram();
work->SetHour(12);
work->WriteProgram();
work->SetHour(13);
work->WriteProgram();
work->SetHour(14);
work->WriteProgram();
work->SetHour(17);
work->WriteProgram();
work->SetFinish(false);
work->SetHour(19);
work->WriteProgram();
work->SetHour(22);
work->WriteProgram();
system("pause");
return 0;
}
原因分析:
从错误信息看,应该是将std::shared_ptr转换为std::shared_ptr失败导致的,但是很奇怪,类ForenoonState是State类的子类,子类转换为父类有什么问题?看了ForenoonState类的声明与定义发现,之前为了能够在Work类中使用ForenoonState类,将ForenoonState类的声明放在Work类的定义前,但是只有在类的定义中才有继承关系,但是由于ForenoonState类的依赖关系,必须把它的定义放在Work类的后面。
解决方案:
这该怎么办呢?头疼了半天,在网上也没有搜到相应的结果,关键是不好描述这个问题。但是呢,灵机一动,突然想到,可以先将类的完整信息声明出来啊,比如有哪些属性,有哪些函数接口,具体实现可以放到后面来做。对于上述问题,不就是将Work类的构造函数先声明,然后在ForenoonState类的定义后面实现Work类的构造函数不久可以了,想到就做到。
Work类构造函数声明更改:
class Work
{
private:
...
public:
Work();
Work类构造函数定义实现:
class ForenoonState : public State
{
...
};
Work::Work() : hour(0), finish(false), smartState(std::make_shared<ForenoonState>()) {}
注意要将Work类构造函数放在ForenoonState类定义的后面。
问题解决!编译成功,运行OK, Nice!!!
看来,仅仅声明子类,当将子类转换为父类对象时,编译器是无法知道子类与父类间的继承关系的,之前都没有注意到!!!
|