访问虚函数中的派生类成员变量
Access derived class member variable in virtual function
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() {}
}
所有的state都是从BaseState派生的,所以它们有成员变量mVehicle来访问外部类变量。但是,在每个派生类中,在每个State的所有函数中,都需要static_cast来访问派生类的成员变量和函数。
有更好的解决方案吗?
- 在派生类的每个State中,添加另一个指针(例如,Convertible *mConvertible)。每个State都有指向同一个对象的重复指针(mConvertible和mVehicle)。
- 在基类中使用虚Getter代替mVehicle。在基类中会有过多的Getter调用。
=======================================================================
是的。我尝试了下面的模板,但它无法编译,因为错误如
" Car .h:在成员函数' virtual 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
对象。如果有自动强制转换,则不需要模板。
使用模板
从Car
内部类中移除指针(使它们成为充满纯虚函数的抽象类)。
添加新的模板类CarT
(或考虑更好的名称)
template <typename T>
class CarT {
class CarHolder {
explicit CarHolder(T* car) : car(car) {}
T* car;
};
class State1 : public Car::State1, protected CarHolder {
explicit State1(Car* vehicle) : CarHolder(vehicle) {}
virtual void run() {
// use data of Car
...
doSomething();
}
virtual void doSomething() {
}
};
class State2 : public Car::State2 {
};
...
};
这样你将有Car
的运行时多态性,它的State
和派生类的良好编译时多态性(这反过来又将消除丑陋的static_cast
的需要)
class Convertible: public CarT<Convertible> {
typename CarT<Convertible> Base;
class State1 : public Base::State1 {
explicit State1(Convertible* vehicle) : Car::State1(vehicle) {}
virtual void doSomething() {
car->foldTop();
}
}
class State2 : public Base::State2 {
}
...
void foldTop() {}
}
class Convertible : public CarT<Convertible>
可能看起来很奇怪,但它会工作(CarT
使用它的模板参数仅作为指针,如果它使用它作为值成员可能会有一些问题)
此实现不使用强制类型转换、重复指针、虚拟getter或CRTP。它有三个并行层次:
- 汽车
- 抽象汽车状态,纯抽象接口
- 具体的汽车状态,其中状态由汽车的实际运行类型参数化。
所以我们有例如
Car Car::AbstractState Car::State<C>
| | |
+--- Convertible +--- Convertible::AbstractState +--- Convertible::State<C>
| | | | | |
| +--- Racer | +--- Racer::AbstractState | +--- Racer::State<C>
+--- Hybrid +--- Hybrid::AbstractState +--- Hybrid::State<C>
每个具体状态都派生并实现了相应的抽象状态。如果我们有一个Car*
,它指向Convertible
,我们查询它的状态,我们得到一个Car::AbstractState*
,它指向一个具体的状态对象,最终类型是Convertible::State<Convertible>
。然而,car层次结构的用户不知道也不关心模板机制。
代码:
#include <iostream>
using namespace std;
struct Trace
{
Trace(const char* s) : s (s)
{
cout << s << " startn";
}
~Trace()
{
cout << s << " endn";
}
const char* s;
};
struct Car {
struct AbstractState
{
virtual void run() = 0;
};
template <typename C>
struct State : virtual AbstractState
{
explicit State(C* vehicle) : mVehicle(vehicle) {}
virtual void run()
{
Trace("Car::State::run");
doSomething();
};
virtual void doSomething()
{
Trace("Car::State::doSomething");
}
C* mVehicle;
};
virtual AbstractState* getState() { return new State<Car>(this); }
};
struct Convertible : Car {
struct AbstractState : virtual Car::AbstractState
{
virtual void runBetter() = 0;
};
template <typename C>
struct State : Car::State<C>, virtual AbstractState
{
using Car::State<C>::mVehicle;
explicit State(C* vehicle) : Car::State<C>(vehicle) {}
void doSomething()
{
Trace("Convertible::State::doSomething");
Car::State<C>::doSomething();
mVehicle->foldTop();
}
void runBetter()
{
Trace("Convertible::State::runBetter");
run();
doSomethingElse();
};
virtual void doSomethingElse()
{
Trace("Convertible::State::doSomethingElse");
}
};
void foldTop()
{
Trace("Convertible::foldTop");
}
Convertible::AbstractState* getState() { return new State<Convertible>(this); }
};
int main ()
{
Car car;
Convertible convertible;
Car& car2(convertible);
cout << "runing carn";
Car::AbstractState* carstate = car.getState();
carstate->run();
cout << "runing convertiblen";
Convertible::AbstractState* convertiblestate = convertible.getState();
convertiblestate->run();
cout << "runing car2n";
Car::AbstractState* carstate2 = car2.getState();
carstate2->run();
}
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 内置函数可查看CPP中的成员变量
- 是否可以初始化不可复制类型的成员变量(或基类)
- 将包含C样式数组的对象初始化为成员变量(C++)
- 为什么我不能在一个类的不同行中声明和定义成员变量?
- 在循环中按顺序遍历成员变量
- c++类声明时,相同的例程,不同的成员变量类型
- 如何从另一个文件继承私有成员变量和公共函数
- 在C++类中,是否必须初始化作为数组的成员变量
- 如何从子成员函数修改父公共成员变量
- 我可以在 C++ 中将数据成员/变量从其定义之外添加到结构中吗?
- 从私有成员变量的成员方法返回unique_ptr
- 在派生类中使用基类的私有成员变量的最佳方法
- 静态 constexpr 类成员变量对多线程读取是否安全?
- C++:是否可以使用非静态成员变量模板?
- 打印所有继承的类成员变量和方法
- 如何在复杂继承中访问静态成员变量
- 为什么我不能在返回 const 的布尔函数中为类成员变量赋值?C++
- 成员变量与函数概念检查