2

I'm deriving a new class from the VCL TStream class:

// 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 declares the following two variants of Seek:-

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

But I get the following W8022 warning when compiling my class:-

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

Surely the Using declaration should fix that?

To drag this question back on track, I'm aware of the way that the two versions of TStream::seek interrelate, and I'm just trying to get inherited Seek(int,int) method exposed by the derived class. Why isn't my using declaration doing that?

Roddy
  • 66,617
  • 42
  • 165
  • 277
  • Sorry - clicked "post" too soon! – Roddy Dec 18 '12 at 16:31
  • The problem is that the function declaration differs only by return type. You'll have to post the parent class for us to give further details. – Thomas Matthews Dec 18 '12 at 16:41
  • @ThomasMatthews: The parent class Seek definition is here: http://docwiki.embarcadero.com/Libraries/XE3/en/System.Classes.TStream.Seek – Roddy Dec 18 '12 at 17:24

2 Answers2

4

Roddy, your code is very much correct.

The code works as expected (tested) when adding using TStream::Seek; otherwise as the warning states, will hide the base class method. (this part of C++ language, Remy have to disagree for the first time with you).

The warning is a false positive, a very old and not yet correcred BUG in C++ Builder present at least from version 2006 to XE4.

Niki
  • 558
  • 4
  • 10
  • Thanks for the QC link. I'd expect that the 64-bit Clang-based compiler in XE4 does fix this. – Roddy Sep 06 '13 at 18:34
2

You do not need the using statement at all, so get rid of it. You are overriding the 64-bit Seek() method. That is all you need to do. You get the 32-bit Seek() method for free since it is a public method of TStream and you are using public inheritance on your derived class. You do not have to declare anything to get or use the 32-bit Seek() method. As long as you do not override it, it will internally call your 64-bit overriden Seek() if called.

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

FYI, if all you need is to delete the temp file when the stream is closed, you don't need a derived class at all. You can use the RTL's THandleStream as-is instead, passing it a HANDLE from the Win32 API CreateFile() function, where you specify the FILE_FLAG_DELETE_ON_CLOSE flag to CreateFile().

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • +1 for the THandleStream suggestion, but I actually need to fix the warning: The Using declaration is mean to do that, by exposing the base class signatures - but the warning is still there. AFAIK, if the warning is NOT fixed then code calling Seek(int,int) goes directly to the derived class, rather than via the base class method. For TStream, that has basically the same effect, but in the general case it's probably a bad idea. – Roddy Dec 18 '12 at 19:32
  • Again, the `using` statement is the **WRONG** thing to use in this situation. You **DO NOT** need it. `TSeekOrigin` is declared as an enum. You cannot pass an `int` to it without using a type-cast. Any code that is calling `Seek(int, int)` will call the 32-bit `Seek()`, which will then call your overriden 64-bit `Seek()` internally. `TSeekOrigin` was implemented as an enum specifically to cause that behavior, so pre-existing code expecting the 32-bit `Seek()` would not break when the 64-bit `Seek()` was introduced. Code wanting to call the 64-bit `Seek()` has to use `TSeekOrigin` correctly. – Remy Lebeau Dec 18 '12 at 19:43
  • I think that's not correct: Look at the following code:- `TFileStream *ss = new TFileStream()); TStream *s(ss); s->Seek(0,0); ss->Seek(0,0); `. The first seek() compiles fine, but the second gives a warning `W8006 Initializing TSeekOrigin with int` so a: It's NOT calling the inherited (int,int) version, and b:no typecast was needed...? Anyhow, the main reason for the question is how to get rid of the W8022 warning, and removing the `using` isn't doing that. – Roddy Dec 18 '12 at 21:27
  • OK, there's something peculiar here. From some more (non-TSTream) tests I think the using declaration is working as I expect, BUT the warning message is output regardless, which is just odd. – Roddy Dec 18 '12 at 22:03
  • 1
    There is no `Seek(int, int)` overload. There is only `Seek(int, unsigned short)` and `Seek(const __int64, TSeekOrigin)`. `Seek(0, 0)` matches the former, not the latter. I was able to reproduce the issue in XE2. I think this is a compiler bug. The `using` statement should not be needed. It does not exist in standard VCL `TStream` classes, and they work just fine without emitting any warning/error. Your overridden `Seek()` is a proper override, it does not hide anything. The compiler is wrong. – Remy Lebeau Dec 19 '12 at 00:01