【问题标题】:Calling non-template base class constructor in class derived from templated intermediary在从模板化中介派生的类中调用非模板基类构造函数
【发布时间】:2011-10-05 12:24:41
【问题描述】:
template <class WndClass>
class screenhelpers : public WndClass
{
public:
    typedef WndClass BaseClass;
    typedef typename screenhelpers<WndClass> ThisClass;
    CRect GetControlRect(CWnd *pControl) const
    {               
            CRect rectWindow(0,0,0,0);
            if (!pControl)
                    return rectWindow;
            pControl->GetWindowRect(&rectWindow);
            this->ScreenToClient(&rectWindow);
            return rectWindow;
    }
};

class MyDialog : public screenhelpers<CDialog>
{
public:
    typedef screenhelpers<CDialog>::BaseClass MDialog;
    MyDialog(int i);
    MyDialog(LPCSTR lpszTemplateName, CWnd *pParentWnd);
    MyDialog(int nIDTemplate, CWnd *pParentWnd);
};

MyDialog::MyDialog(int i)
{
    BaseClass b;    
}

MyDialog::MyDialog(LPCSTR lpszTemplateName, CWnd *pParentWnd)
:    MyDialog::BaseClass(lpszTemplateName, pParentWnd)
{    
}


MyDialog::MyDialog(int nIDTemplate, CWnd *pParentWnd)
    :       MyDialog::CDialog(nIDTemplate, pParentWnd)
{
}

我不明白为什么我似乎无法调用屏幕助手的基类。

如果MyDialog继承自screenhelpers,screenhelpers继承自CDialog,为什么不能调用CDialog?

【问题讨论】:

  • 我有另一个简化的例子class Bob { public: Bob() : t(12){} Bob(int i) : t(i){} int t; }; template &lt;class Base&gt; class Bill : public Base { public: Bill() : s(20){} typedef Base BaseClass; int s; }; class it : public Bill&lt;Bob&gt; { public: it(int i) { s = i; t= 1;} //Create equivalent of above line that explicitly intialises the t that resides in Bob #if 1//My unworking attempt it (double d) : BaseClass(30) {} #endif };
  • it 构造函数正在修改 Bob 的成员 t,从而证明基类 Bob 存在于其中
  • 如果您指出您遇到的错误会有所帮助,我不得不在我的答案中猜测。
  • 哎呀。当尝试使用 typedef error C2614: 'MyDialog' : illegal member initialization: 'BaseClass' is not a base or member
  • 当尝试使用 CDialog error C2614: 'MyDialog' : illegal member initialization: 'CDialog' is not a base or member

标签: c++ templates mfc constructor base-class


【解决方案1】:

构造函数中的初始化列表只能调用其直接父级的构造函数,而不是更上一层的构造函数。所以不能直接初始化CDialog。

您的 screenhelpers 类没有定义一个带有两个参数的构造函数,所以这也不起作用。即使您添加了这样的构造函数,我也不确定通过 typedefed 名称引用它的语法是否有效,您可能需要改用 screenhelpers&lt;CDialog&gt;。

【讨论】:

  • GCC 4.6.1 说:“错误:ISO C++ 禁止嵌套类型 'screenhelpers' 与封闭类 [-fpermissive] 同名”也就是说,类类型本身的类 typedef 不真的很有意义,因为你已经拥有类的类型了。
  • @Kerrek - ThisClass typedef 没问题,但也许跳过不正确的typename 会让编译器更快乐?
  • @Bo:确实会! :-) 那么......(为什么)这是一个有用的想法?
  • @Kerrek 你能解释一下吗?
  • @Stone:我的意思是,你为什么需要 typedef 来引用你已经拥有的类型?假设你说typedef screenhelpers&lt;CrazyClass&gt; Foo;。现在你有了Foo::ThisClass,但是为什么,它和Foo一样!什么情况下需要ThisClass?
【解决方案2】:

如果允许MyDialog 构造函数调用CDialog 构造函数,则后者将被调用两次:一次由MyDialog 调用,一次由screenhelpers 调用。那将是一场灾难。

如果需要控制如何从MyDialog调用CDialog构造函数,则需要使用虚拟继承:

template <class WndClass>
class screenhelpers : public virtual WndClass

然后您将拥有(不仅仅是能够)从MyDialog 调用CDialog 构造函数。

请注意,这可能会对您的设计产生其他影响。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-23
    • 1970-01-01
    • 2021-04-20
    • 2016-08-17
    • 2019-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多