4

我希望 C 类从 A 类继承其虚函数,而 D 类(C 类中的嵌套类)从 B 类(A 类中的嵌套类)继承其数据字段,这就是我所拥有的。

文件1.h

class A{
 public:
     virtual void foo()=0;
     class B{
       public:
         int data;
     };
};

文件2.h

class C : public A{
 public:
     class D : public A::B{

     };    
};

文件2.cpp

void C::foo(){//code}
C::D::D():data(0){//Bad initialization list, error being data is not a member of C::D even it should inherits from its base class
 data = 0; //good! compiler can see data is a member of A::B,and C::D inherits from it
}

我有两个问题,第一个是我正在做的正确方法来实现这种继承。其次,正如我所评论的,为什么编译器可以在手动初始化过程中看到数据来自 A::B 而不是在初始化列表中?他们不应该在同一个范围内吗?非常感谢你

编辑1

因此,如果类 C::D(foo) 不直接继承自 A::B(foo),而是 C 继承自 A,我的看法是,由于 C 继承自 A 及其所有公共字段,包括其内部类 A ::B(foo), D(foo) 与 A::B(foo) 具有完全相同的名称,并且是 C 的内部类,就像这样,即 foo 用于两个内部类

class A{
 public:
     class foo{
       public:
         int data;
     };
};

class C : public A{
 public:
     class foo{

     };    
};

当我直接调用 C::foo 时,编译器会感到困惑吗?因为范围内有两个具有名称的构造函数?或者它选择调用“最近的”,例如 C:foo?而不是爬上继承链?非常感谢你

4

4 回答 4

4
  1. 是的,您的方法是实现这种继承的正确方法。

  2. 初始化列表用于控制传递给构造函数的参数。您可以将参数传递给 B 的构造函数,但不能直接初始化 B 的成员(这是其构造函数的工作)。如果没有为基类或成员指定构造函数,则使用默认构造函数。在您的情况下,将构造函数添加到 B 以实现您想要的。

    class A {
    public:
        class B{
        public:
            B(int i) : data(i) {}
            int data;
        };
    }; 
    
    class C : public A {
        class D : public A::B {
        };
    };
    
    C::D::D() :B(0) { }
    
于 2012-09-17T15:50:37.780 回答
3

句法的角度来看,它是正确的(*1)。当然,除了初始化列表。您只能在初始化列表中初始化当前类成员(而不是基类成员)。这与嵌套无关。

class X
{
public: 
   int x;
};
class Y : X
{
   Y() : x(0) {} //still illegal
};

我说句法 POV 是因为这是一件很奇怪的事情……我相信有一种更简洁的方法可以实现您真正想要的。

于 2012-09-17T15:49:19.920 回答
1

您从嵌套类继承的语法是正确的。

初始化列表用于初始化该类的成员;基类成员应该在基类构造函数中初始化。

于 2012-09-17T15:50:24.850 回答
0

从语法上讲,接受的答案很好地回答了您的问题。这是我在与机制相关的设计方面的两分钱:在您的示例中,抽象类 A 本质上是一个接口。接口应该只定义行为和行为。话虽如此,我认为在接口中有一个嵌套类是没有意义的。

1)接口没有任何数据成员可以由嵌套类操作,就像您的示例一样。这首先消除了对嵌套类的需要。

2)嵌套类不是行为。所以它不应该出现在界面中。

现在您可能会争辩说您的示例只是一个快速演示,实际上您会有数据成员供嵌套操作,即 A 类不是纯接口。您只是想为嵌套的 B 类提供一个默认实现,并让 C 类决定他想如何将 B 类自定义为他自己的 D 类。如果是这样的话,恐怕设计会更糟。

3)考虑迭代器模式。A类本质上是一个不能被实例化的抽象容器(因为你里面有一个纯虚函数)——让我们把它映射到我们脑海中的IContainer。现在你创建了一个类 C,它有一个向量/数组实现,他自己的迭代器 D 指向数组中的某个元素。

然后你想创建另一个类 E,它有一个哈希映射实现,她自己的迭代器 F 指针指向哈希映射中的某个对。

这是灾难:在包含类(C,E ...)的实现中,您通常无法在所有迭代器类(D,F ...)中拥有统一的接口 - 很可能(考虑赋值运算符BIterator operator=(const BIterator& other);:) , D 类有一个接受 D 类对象作为参数的函数DIterator operator=(const DIterator& other):F 类有一些接受 F 类对象作为参数的函数FIterator operator=(const FIterator& other)

另一方面,这是行不通的,因为 DIterator 和 FIterator 都是 BIterator 的子类 - 您不能使用“更窄”(或“更具体”)参数覆盖函数,因为它违反了参数类型的逆变性( C++ 不允许逆变参数,因此它需要匹配参数类型;所以从技术上讲,您可以FIterator operator=(const BIterator& other)为类 F 并执行从 BIterator 到 FIterator 的运行时动态转换——但这很丑陋而且没有意义:一个具体的苹果有一个赋值运算符,将抽象的“水果”分配给自身)。你只是让自己陷入了两难境地。

综上所述,由于 1) 2) 和 3) 的原因,不要在接口/抽象基类中包含嵌套类。迭代器模式只是一个示例,只要嵌套类与包含类交互,就可能在很多情况下让您自责。如果不是,那么一开始就没有嵌套类。

于 2015-01-06T12:14:52.297 回答