I have tried to use this code in VS2008 (and may have included too much context in the sample…):
class Base
{
public:
void Prepare() {
Init();
CreateSelectStatement();
// then open a recordset
}
void GetNext() { /* retrieve next record */ }
private:
virtual void Init() = 0;
virtual string CreateSelectStatement() const = 0;
};
class A : public Base
{
public:
int foo() { return 1; }
private:
virtual void Init() { /* init logic */ }
virtual string CreateSelectStatement() { /* return well formed query */ }
};
template<typename T> class SomeValueReader : protected T
{
public:
void Prepare() { T::Prepare(); }
void GetNext() { T::GetNext(); }
T& Current() { return *this; } // <<<<<<<< this is where it is interesting
SomeValue Value() { /* retrieve values from the join tables */ }
private :
string CreateSelectStatement() const
{
// special left join selection added to T statement
}
};
void reader_accessAmemberfunctions_unittest(...)
{
SomeValueReader<A> reader();
reader.Prepare();
reader.GetNext();
A a = reader.Current();
int fooresult = a.foo();
// reader.foo() >> ok, not allowed
Assert::IsEqual<int>( 1, fooresult );
};
This works as expected, i.e. having access to “A” member functions and fooresult returning 1. However, an exception is thrown when objects are deleted at the end of the unittest function:
System.AccessViolationException:
Attempted to read or write protected
memory. This is often an indication
that other memory is corrupt
If I change the return type of Current() function to :
T* Current()
{
T* current = dynamic_cast<T*>(this);
return current;
}
then everything is ok and the unit test ends with no access violation. Does someone can tell me what was wrong with the first Current() implementation? Thanks, bouchaet.
After changing CreateSelectStatement to return a value for the implemented functions (not the pure virtual)
and changing the declaration of reader (the declaration you have should strictly be interpreted as a function prototype in C++)
The above example compiles and executes without errors using gcc, leading me to believe the actual error may not be present in the source above. Unfortunately I’m unable to test with VC at the moment.
I can’t see any obvious reason why the change you have suggested would resolve the issue, the only other error I can see is that Base does not have a virtual destructor declared meaning that if you ever delete a Base* (or some other derived class that is not the actual type) the incorrect destructor(s) will fire. You should declare it as
even if it’s empty.
Stylistically it’s also a little odd to use templates and virtual functions in this fashion because here you’re using the template to resolve functions at compile time. I can’t see a reason why SomeValueReader needs to derive from T (rather than have a member variable) either.