【问题标题】:"Using declaration" not working in RADStudio 2010“使用声明”在 RADStudio 2010 中不起作用
【发布时间】:2012-12-05 22:02:29
【问题描述】:

我正在从 VCL TStream 类派生一个新类:

// A stream based on a temporary file, deleted when the stream is closed

class TTempFileStream : public TStream
{
...
public:
  using TStream::Seek;

   __int64 __fastcall Seek(const __int64 Offset, TSeekOrigin Origin)
  {
    return 0; // for simplicity!
  }

  ... 
} ;

TStream 声明了以下两个 Seek 变体:-

virtual int __fastcall Seek(int Offset, System::Word Origin)/* overload */;
virtual __int64 __fastcall Seek(const __int64 Offset, TSeekOrigin Origin)/* overload */;

但我在编译我的类时收到以下 W8022 警告:-

[BCC32 Warning]_utils.h(166): W8022 
'_fastcall TTempFileStream::Seek(const __int64,TSeekOrigin)' hides virtual function '_fastcall TStream::Seek(int,unsigned short)'

Using 声明肯定可以解决这个问题吗?

为了把这个问题拖回正轨,我知道两个版本的 TStream::seek 相互关联的方式,我只是想获得派生类公开的继承 Seek(int,int) 方法.为什么我的using 声明不这样做?

【问题讨论】:

  • 抱歉 - 点击“发布”太快了!
  • 问题在于函数声明的不同仅在于返回类型。您必须发布父类以便我们提供更多详细信息。
  • @ThomasMatthews:父类Seek定义在这里:docwiki.embarcadero.com/Libraries/XE3/en/…

标签: c++ c++builder c++builder-2010 using-declaration


【解决方案1】:

Roddy,您的代码非常正确。

使用 TStream::Seek 添加时,代码按预期工作(经过测试);否则如警告所述,将隐藏基类方法。 (这部分C++语言,Remy第一次和你不服)。

警告是误报,C++ Builder 中的一个非常古老且尚未更正的BUG 至少从 2006 版到 XE4 存在。

【讨论】:

  • 感谢 QC 链接。我希望 XE4 中基于 Clang 的 64 位编译器能解决这个问题。
【解决方案2】:

你根本不需要using 语句,所以去掉它。您正在覆盖 64 位 Seek() 方法。这就是你需要做的。您可以免费获得 32 位 Seek() 方法,因为它是 TStream 的公共方法,并且您在派生类上使用 public 继承。您无需声明任何内容即可获取或使用 32 位 Seek() 方法。只要您不覆盖它,它就会在内部调用您的 64 位覆盖 Seek()(如果调用)。

class TTempFileStream : public TStream
{
...
public:
    ...
    virtual __int64 __fastcall Seek(const __int64 Offset, TSeekOrigin Origin)
    {
        return 0; // for simplicity!
    }
    ... 
};

仅供参考,如果您只需要在流关闭时删除临时文件,则根本不需要派生类。您可以按原样使用 RTL 的 THandleStream,从 Win32 API CreateFile() 函数向其传递 HANDLE,在该函数中将 FILE_FLAG_DELETE_ON_CLOSE 标志指定给 CreateFile()

【讨论】:

  • +1 用于 THandleStream 建议,但我实际上需要修复警告: Using 声明的意思是通过公开基类签名来做到这一点 - 但警告仍然存在。 AFAIK,如果未修复警告,则调用 Seek(int,int) 的代码将直接转到派生类,而不是通过基类方法。对于 TStream 来说,效果基本相同,但一般情况下这可能是个坏主意。
  • 同样,using 语句是在这种情况下使用的 错误 事物。你需要它。 TSeekOrigin 被声明为枚举。如果不使用类型转换,您不能将 int 传递给它。任何调用Seek(int, int) 的代码都将调用32 位Seek(),然后它会在内部调用您覆盖的64 位Seek()TSeekOrigin 被实现为一个专门用于导致该行为的枚举,因此当引入 64 位 Seek() 时,预期 32 位 Seek() 的预先存在的代码不会中断。想要调用 64 位 Seek() 的代码必须正确使用 TSeekOrigin
  • 我认为这是不正确的:看下面的代码:-TFileStream *ss = new TFileStream()); TStream *s(ss); s->Seek(0,0); ss->Seek(0,0); 。第一个 seek() 编译得很好,但第二个给出警告 W8006 Initializing TSeekOrigin with int 所以 a: 它没有调用继承的 (int,int) 版本,并且 b: 不需要类型转换......?无论如何,这个问题的主要原因是如何摆脱 W8022 警告,而删除 using 并没有这样做。
  • 好的,这里有一些特别之处。从更多(非 TSTream)测试中,我认为 using 声明按预期工作,但无论如何都会输出警告消息,这很奇怪。
  • 没有Seek(int, int) 过载。只有Seek(int, unsigned short)Seek(const __int64, TSeekOrigin)Seek(0, 0) 匹配前者,而不是后者。我能够在 XE2 中重现该问题。我认为这是一个编译器错误。不需要using 语句。它在标准 VCL TStream 类中不存在,它们工作得很好,不会发出任何警告/错误。您覆盖的 Seek() 是一个正确的覆盖,它不会隐藏任何东西。编译器错误。
猜你喜欢
  • 2015-08-13
  • 1970-01-01
  • 2017-02-12
  • 1970-01-01
  • 1970-01-01
  • 2018-10-02
  • 2013-07-13
  • 1970-01-01
相关资源
最近更新 更多