2

考虑以下 :

#include <iostream>
#include <string>
using namespace std;


class A {
public:
   A(const char* sName) //conversion constructor
           : _sName(sName) {cout<<"(1)"<<endl;} ;
   A(const A& s) {cout<<"(2)"<<endl;} //copy constructor
   virtual ~A() {cout<<"(3)"<<endl;} //destructor
    void f1() {cout<<"(4)"<<endl; f2();} //Notice two commands!
    virtual void f2() =0;
  private:
    string _sName;
  };



  class B1: virtual public A {
  public:
     B1(const char* sAName, const char* sSName)
             : _sName1(sAName), A(sSName) {cout<<"(5)"<<endl;}
     B1(const B1& b1) : A(b1) {cout<<"(6)"<<endl;}
     ~B1() {cout<<"(7)"<<endl;}
     virtual void f1() {cout<<"(8)"<<endl;}
     virtual void f2() {cout<<"(9)"<<endl; f3();}
     virtual void f3() {cout<<"(10)"<<endl;}
  private:
     string _sName1;
  };



  class B2: virtual public A {
  public:
     B2(const char* sAName, const char* sSName)
             : _sName2(sAName), A(sSName) {cout<<"(11)"<<endl;}
     B2(const B2& b2) : A(b2) {cout<<"(12)"<<endl;}
     ~B2() {cout<<"(13)"<<endl;}
     virtual void f3() {f1(); cout<<"(14)"<<endl;}
  private:
      string _sName2;
  };

  class C: public B1, public B2 {
  public:
         C () : A(" this is A ") , B1(" this is " , " B1 ") , B2 (" this is " , " B2 ") {}
         C (const C& c) :  A(c) , B1(c) , B2(c) {}
         ~C() {cout<<"(15)"<<endl;}
         virtual void f1() {A::f1(); cout<<"(16)"<<endl;}
         void f3 () {cout<<"(17)"<<endl;}
  };


  int main() {
      /* some code */
      return 0;
  }

如您所见,我在class CC的实现中添加了Ctor(构造函数)。我不清楚的是,如果 B1 在其 Ctor 中为我完成这项工作,为什么我还需要从 C 到 A 的向上转换?意思是,如果我将 C 的 Ctor 写为:

C () : A(" this is A ") , B1(" this is " , " B1 ") , B2 (" this is " , " B2 ") {}

为什么我不能写:

C () : B1(" this is " , " B1 ") , B2 (" this is " , " B2 ") {}

谢谢,罗南

4

5 回答 5

2

虚拟基础的构造函数在非虚拟分析器 ctor之前调用。在您的示例中,B1 ctor 无法调用 C 的虚拟基础构造函数,因为稍后将调用 B1 ctor 本身。

于 2011-09-01T08:27:44.753 回答
2

简而言之,因为这是标准所要求的:您必须在最派生类的 ctor 中初始化虚拟基。

一个更详细的答案,这是因为您只有一个用于虚拟基础的基础子对象,并且该子对象可能在不同的基类中以不同方式初始化。例如在你的例子中


C () : B1(" this is " , " B1 ") , B2 (" this is " , " B2 ") {}

您希望将什么值传递给 A ctor、“B1”或“B2”?

于 2011-09-01T08:23:22.170 回答
1

这是一个快速尝试:

#include <iostream>

class A { public: A(int v) : m_v(v) { std::cout << "Initializing A with " << v << std::endl; } int m_v; };
class B1 : public virtual A { public: B1(int v) : A(v) {} };
class B2 : public virtual A { public: B2(int v) : A(v) {} };
class C : public B1, public B2 { public: C(int v1, int v2, int v3) : A(v1), B1(v2), B2(v3) {} };

int main()
{
    C c(1, 2, 3);

    std::cout << "c.m_v: " << c.m_v << std::endl;

    return EXIT_SUCCESS;
}

此示例输出:

Initializing A with 1
c.m_v: 1

也就是说,似乎A::A()在最派生类中调用 to 是必需的,因为由于继承是virtual,它不会被 的构造函数B1B2实例化时调用C

于 2011-09-01T08:28:44.523 回答
1

因为“B1”和“B2”都使用与“C”相同的内存来存储“A”。如果你没有在'C'中指定'A'的构造,'B1'或'B2'中的哪一个应该构造'A'?

您的术语在这里略有错误-这不是对“ A”的向上转换。

于 2011-09-01T08:22:29.440 回答
1

因为您class A没有默认构造函数。

编译器为每个类生成一个默认构造函数,但是一旦你显式地重载构造函数,它就会假设你想要做一些特殊的事情并且它不会生成默认构造函数,并且当你的代码尝试调用默认构造函数时会导致错误。

以下代码语句:

C () : B1(" this is " , " B1 ") , B2 (" this is " , " B2 ") {}

导致调用 A 类默认构造函数,该构造函数根本不存在,因此导致错误。如果您为您提供了一个默认构造函数,class A那么它也应该可以正常编译而不会出现任何错误。

于 2011-09-01T08:23:37.127 回答