【问题标题】:Overriden Virtual methods not being called覆盖未调用的虚拟方法
【发布时间】:2013-03-12 04:08:28
【问题描述】:

我正在尝试创建一个抽象类,其他一些类可以作为 arduino 项目的基础。但是,每当我调用基础中的虚拟方法时,它只会调用基础实现。代码如下。谁能看到我做错了什么?

#define RTCBASE 0
class RTC_Base {
public:
  virtual uint8_t begin(void){ return 0; };
  virtual void adjust(const DateTime& dt){};
  virtual DateTime now(){ return DateTime(); };
  virtual int Type(){ return RTCBASE; };
};
////////////////////////////////////////////////////////////////////////////////
// RTC based on the DS1307 chip connected via I2C and the Wire library
#define DS1307 1
class RTC_DS1307 : public RTC_Base 
{
public:
  virtual int Type(){ 
    return DS1307; 
  }
  uint8_t begin(void);
  void adjust(const DateTime& dt);
  uint8_t isrunning(void);
  DateTime now();
  uint8_t readMemory(uint8_t offset, uint8_t* data, uint8_t length);
  uint8_t writeMemory(uint8_t offset, uint8_t* data, uint8_t length);


};

///In Code
RTC_Base RTC = RTC_DS1307();
DateTime dt = RTC.now();
//The above call just returns a blank DateTime();

【问题讨论】:

  • 也许您正在体验对象切片。
  • 您是 1) 在派生类中定义函数 2) 不是切片,对吗?此外,一个类不是抽象的,除非它至少有一个纯虚成员函数,而你的则没有。
  • 您必须展示您的使用示例。类实例是怎么创建的,怎么变成基类的,又是怎么调用函数的?
  • 抱歉...添加了示例。什么是切片?也许抽象是错误的术语......我很难让编译器对纯虚拟很酷,所以我把它们去掉了。
  • 部分地,当我尝试使用纯虚拟时,它不会让我这样做:RTC_Base RTC;我想这样做,以便我可以决定在运行时使用哪个派生类。

标签: c++ inheritance arduino abstract-class


【解决方案1】:

你有代码:

RTC_Base RTC = RTC_DS1307();
DateTime dt = RTC.now(); //The above call just returns a blank DateTime();

那是object slicing(正如@chris 最初猜测的那样)。要使Polymorphism 工作,您必须假装派生类是基类,将指针或引用 视为基类,而实际上它是派生类的地址。 (因为 Derived 实际上包含其中的 Base)。

Derived myDerived;
Base &myBaseRef = myDerived;

myBaseRef.myVirtualFunction();

否则,您将创建 Derived,并尝试将字节强制转换为 Base,并丢失所有 Derived 的字节。这样不好! =)

关键是,您实际上不应该 Derived 转换为Base,而只是像访问Base 一样访问Derived。如果将其转换为 Base,则它一个 base。并且您的 Base 类返回一个空的 DateTime。

要使用动态分配的内存,您可以这样做:

Base *myBase = nullptr; //Or 'NULL' if you aren't using C++11
myBase = new Derived;

myBase->myVirtualFunction(); //Dereference the myBase pointer and call the function.

delete myBase; //Free the memory when you are finished.

如果你使用的是 C++11,你可以让std::unique_ptr为你处理对象的生命周期,这样你就不必记得调用'delete'了:

std::unique_ptr<Base> myBase;

//Later...
myBase = new Derived;
myBase->myVirtualFunction();

//Automatically freed when the myBase smart pointer goes out of scope...

【讨论】:

  • 认为有道理...有没有一种好方法可以做到这一点,以便 RTC_Base &RTC 可以成为一个全局变量(并且在设置之前不设置( ) 方法)?另外,是否有可能做到这一点并且仍然让基础包含纯虚拟?
  • 当我尝试在没有立即初始化的情况下将其设为全局时,我只是收到“错误:'RTC' 声明为引用但未初始化”
  • 当然,使用指针而不是引用。 RTC_Base *globalBase = NULL;后来: globalBase = new Derived;只要确保您在 globalBase 上调用“删除”,因为您正在动态分配内存。 (“删除”你“新”的所有内容)
  • 我实际上是在 arduino 上做这个的,所以看起来有点不同,但这让我更接近了。而且我可能真的不需要调用 delete,因为只要控制器正在运行,这个对象就存在:P
  • 现在知道了 :) 感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-19
  • 2014-03-18
  • 2012-10-26
  • 1970-01-01
  • 2011-05-21
相关资源
最近更新 更多