如何解决在其他父类实现的c++接口中使用抽象虚函数
我正在尝试定义一个接口(抽象类),它将“自动”将创建的任何实例注册到全局映射,其中键是 uint8_t
,值是指向接口类的指针。>
将实现此接口的所有类都已具有使用 getId()
方法检索唯一 ID 的方法。我已经尝试了以下方法,但是当我在接口的 c'tor 和 d'tor 中使用(当时)抽象方法 getId() 时,它会收到警告,我可以理解。但是当我尝试创建 LightZoneImpl 的实例时出现错误,因为它没有实现 getId()。
我在这里做错了什么?
注意:这是真实事物的简化示例,真实事物中涉及许多其他类等。
class ILightZone; // forward
typedef std::map<uint8_t,ILightZone*> LightZoneMap;
extern LightZoneMap lightZoneMap;
/**
* @brief Interface defining a Lightzone operating node,automatically (de-)registered in the lightZoneMap
*
*/
class ILightZone {
public:
ILightZone() {
lightZoneMap[getId()] = this; // <== warning: pure virtual function called from c'tor
}
virtual ~ILightZone() {
lightZoneMap.erase(getId()); // <== warning: pure virtual function called from d'tor
}
virtual const uint8_t getId() const = 0;
virtual void setLightOn() = 0;
virtual void setLightOff() = 0;
virtual bool isLightOn() = 0;
virtual void setIntensity(const uint8_t percentage) = 0;
virtual uint8_t getIntensity() = 0;
};
class BaseNode {
public:
BaseNode(uint8_t nodeId) : nodeId(nodeId) {};
virtual ~BaseNode() {};
virtual const uint8_t getid() const { return nodeId; };
private:
uint8_t nodeId;
};
class LightZoneImpl : public ILightZone,public BaseNode {
public:
LightZoneImpl() {};
virtual ~LightZoneImpl() {};
using BaseNode::getId;
void setLightOn() override { /* implementation */};
void setLightOff() override { /* implementation */};
bool isLightOn() override { return false; };
void setIntensity(const uint8_t percentage) override { /* implementation */ };
uint8_t getIntensity() override { return 0; };
}
LightZoneImpl zone{12}; // <= error: cannot declare variable 'zone' to be of abstract type LightZoneImpl
class ILightZone; // forward
typedef std::map<uint8_t,automatically (de-)registered in the lightZoneMap
*
*/
class ILightZone {
public:
ILightZone(uint8_t nodeId) : nodeId(nodeId) {
lightZoneMap[nodeId] = this;
}
virtual ~ILightZone() {
lightZoneMap.erase(nodeId);
}
const uint8_t getId() const { return nodeId; };
virtual void setLightOn() = 0;
virtual void setLightOff() = 0;
virtual bool isLightOn() = 0;
virtual void setIntensity(const uint8_t percentage) = 0;
virtual uint8_t getIntensity() = 0;
private:
uint8_t nodeId;
};
class BaseNode {
public:
BaseNode(uint8_t nodeId) : nodeId(nodeId) {};
virtual ~BaseNode() {};
virtual const uint8_t getid() const { return nodeId; };
private:
uint8_t nodeId;
};
class LightZoneImpl : public ILightZone,public BaseNode {
public:
LightZoneImpl(uint8_t nodeId) : ILightZone(nodeId),BaseNode(nodeId) {};
virtual ~LightZoneImpl() {};
using BaseNode::getId;
void setLightOn() override { /* implementation */};
void setLightOff() override { /* implementation */};
bool isLightOn() override { return false; };
void setIntensity(const uint8_t percentage) override { /* implementation */ };
uint8_t getIntensity() override { return 0; };
}
LightZoneImpl zone{12}; // <= error: cannot declare variable 'zone' to be of abstract type LightZoneImpl
解决方法
在构造完成之前,虚拟分派不会开始使用派生类函数覆盖:当时您希望 getId()
会使用派生类覆盖,只是抽象 基础的一部分 类已被构造 - 派生对象不存在以调用其函数。
您可以让派生类或工厂函数提供 id 并在地图上进行操作。
Bascy 要求的详细说明/示例...
您可以将此处涉及的对象视为 LightZoneImpl
对象,其中嵌入了 ILightZone
基类对象。要构造 LightZoneImpl
,必须首先构造基类......而当发生这种情况时,派生类对象不存在或具有派生类构造函数设置的不变量(关于状态的保证),所以现在调用虚函数的任何派生类覆盖还为时过早。出于这个原因,C++ 标准规定应该继续调用基类虚函数实现,但如果它们不可用,因为函数是纯虚函数,您的程序将终止。
要解决此问题,您可以按照 Mooing Duck 在其评论中的建议进行操作,并让派生类指定基类保存的 id。那可能是最好的。您还可以拥有一个创建光区的工厂函数,让派生类构造函数将其传递给基类以供存储/使用:
std::unique_ptr<LightZoneImpl> lz_factory() {
static int id_ = 0;
if (id_ > 255)
throw std::runtime_error("too many lightzones");
return std::make_unique<LightZoneImpl>(id_++);
}
然后您希望将灯区构造函数设为私有,并将工厂设为 friend
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。