c++ - 从模板参数继承并在 C++ 中向上转换

标签 c++ templates casting polymorphism crtp

我曾尝试在 VS2008 中使用此代码(并且示例中可能包含了过多的上下文...):

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 );
};

这按预期工作,即可以访问“A”成员函数并且 fooresult 返回 1。但是,当在 unittest 函数末尾删除对象时会抛出异常:

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt

如果我将 Current() 函数的返回类型更改为:

T* Current()
{
   T* current = dynamic_cast<T*>(this);
   return current;
}

然后一切正常,单元测试以没有访问冲突结束。有人能告诉我第一个 Current() 实现有什么问题吗?谢谢,bouchaet。

最佳答案

更改 CreateSelectStatement 以返回已实现函数(不是纯虚拟函数)的值后

string CreateSelectStatement() const { return ""; }

并更改 reader 的声明(您拥有的声明应严格解释为 C++ 中的函数原型(prototype))

SomeValueReader<A> reader;

上面的示例使用 gcc 编译和执行没有错误,这让我相信实际的错误可能不存在于上面的源代码中。很遗憾,我目前无法使用 VC 进行测试。

我看不出任何明显的理由说明您建议的更改可以解决问题,我能看到的唯一其他错误是 Base 没有声明的虚拟析构函数,这意味着如果您删除了一个 Base*(或一些不是实际类型的其他派生类)不正确的析构函数将被触发。您应该将其声明为

virtual ~Base() {}

即使它是空的。

从风格上讲,以这种方式使用模板和虚函数也有点奇怪,因为在这里您使用模板在编译时解析函数。我也看不出 SomeValueReader 需要从 T 派生(而不是有一个成员变量)的原因。

关于c++ - 从模板参数继承并在 C++ 中向上转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1889137/

相关文章:

c++ - boost::any 析构函数崩溃

c++ - 在指向 vector 的智能指针上使用 push_back() 时出现运行时错误

c++ - 使用策略推导模板参数

javascript - 寻找一行类型转换 Number(oldValue) += 1;在JS中

c++ - 我如何在 QNX 上强制使用特定的线程序列?

c++ - 根据模板参数大小在成员函数中使用不同的返回类型

c++ - 学习 C++ 模板

c++ - 了解模板内定义的模板 (C++)

java - 为什么这个通用转换不会失败?

java - Swing 绘制在不正确的坐标上