class Car {
class BaseState {
explicit BaseState(Car* vehicle) : mVehicle(vehicle) {}
virtual void run() = 0;
Car* mVehicle;
}
class State1 : public BaseState {
explicit State1(Car* vehicle) : BaseState(vehicle) {}
virtual void run() {
// use data of Car
...
doSomething();
}
virtual void doSomething() {
}
}
class State2 : public BaseState {
}
...
}
class Convertible: public Car {
class State1 : public Car::State1 {
explicit State1(Convertible* vehicle) : Car::State1(vehicle) {}
virtual void doSomething() {
static_cast<Convertible*>(mVehicle)->foldTop();
}
}
class State2 : public Car::State2 {
}
...
void foldTop() {}
}
所有状态都是从BaseState派生的,因此它们具有成员变量mVehicle来访问外部类变量 . 但是,在每个派生类中,在每个State的所有函数中,需要static_cast来访问派生类成员变量和函数 .
更好的解决方案?
-
在派生类的每个状态中,添加另一个指针(例如,Convertible * mConvertible) . 每个State都有重复的指针(mConvertible和mVehicle)指向同一个对象 . 看起来不对劲 .
-
在基类中使用虚拟Getter而不是mVehicle . 基类中会有过多的Getter调用 .
================================================== =====================
是 . 我尝试了如下模板,但它无法编译,因为错误就像
“car.h:在成员函数中'虚拟void Car :: State1 :: run()':car.h:18:12:错误:'mVehicle'未在此范围内声明” .
// car.h
#include <iostream>
template <class T>
class Car {
public:
class BaseState {
public:
explicit BaseState(T* vehicle) : mVehicle(vehicle) {}
protected:
T* mVehicle;
};
class State1 : public BaseState {
public:
explicit State1(T* vehicle) : BaseState(vehicle) {}
virtual void run() {
mVehicle->x = 1;
mVehicle->y = 2;
mVehicle->doSomething1();
mVehicle->doSomething2();
processEvent();
}
virtual void processEvent() {
if (mVehicle->val > 2) {
std::cout << "too large" << std::endl;
}
}
};
class State2 : public BaseState {
public:
explicit State2(T* vehicle) : BaseState(vehicle) {}
virtual void run() {
mVehicle->x = 10;
mVehicle->y = 20;
processEvent();
}
virtual void processEvent() {
if (mVehicle->val > 20) {
std::cout << "too large" << std::endl;
}
}
};
virtual void doSomething1() {
val += x * y;
}
virtual void doSomething2() {
val += x + y;
}
protected:
int x;
int y;
int val;
};
// convertible.h
#include "car.h"
#include <iostream>
class Convertible : public Car<Convertible> {
protected:
class State1 : public Car<Convertible>::State1 {
explicit State1(Convertible* vehicle) : Car<Convertible>::State1(vehicle) {}
// want to override functions in base class states
virtual void processEvent() {
if (mVehicle->val > 10) {
std::cout << "too large" << std::endl;
mVehicle->val = 10;
}
}
};
// want to override some base class functions
// and access some special variables
// want to inherit other functions
virtual void doSomething2() {
z = 10;
val += x + y + z;
}
protected:
int z;
};
如果我使用 State1(Car* vehicle)
而不是 State1(T* vehicle)
,则会出现其他转换错误 . 我究竟做错了什么?
如果程序可以确定应该执行 Convertible::State1::processEvent()
,为什么不能自动将 mVehicle
从 Car*
强制转换为 Convertible*
?推导出 Convertible::State1::processEvent()
时,显然 mVehicle
指向 Convertible
对象 . 如果有自动演员,我们不需要模板 .
2 回答
此实现不使用强制转换,重复指针,虚拟getter或CRTP . 它有三个并行的层次结构:
汽车
抽象汽车状态是纯粹的抽象接口
具体汽车状态,其中状态由汽车的实际运行类型参数化 .
所以我们有例如
每个具体状态派生自并实现相应的抽象状态 . 如果我们有
Car*
指向Convertible
,并且我们查询它的状态,我们得到一个Car::AbstractState*
,它指向具有最终类型Convertible::State<Convertible>
的具体状态对象 . 然而,汽车层次结构的用户并不关心模板机制 .代码:
使用模板 .
从
Car
内部类中删除指针(使它们成为充满纯虚拟的抽象类) .添加新模板类
CarT
(或考虑更好的名称)通过这种方式,您将拥有
Car
的运行时多态性,并且它的State
和派生类的良好编译时多态性(这反过来将消除对丑陋static_cast
的需要)class Convertible : public CarT<Convertible>
可能看起来很奇怪,但它会起作用(CarT
仅将模板参数用作指针,如果它将其用作值成员则可能存在一些问题)