【问题标题】:Is it possible for a base class to have a function that's not in the derived class?基类是否有可能具有不在派生类中的函数?
【发布时间】:2015-05-23 22:25:44
【问题描述】:

假设您有一个具有多个功能的基类,例如

virtual int func1();
virtual int func2();
virtual int func3();
virtual int func4();

等等

你想要有两个子类,Child1 和 Child2。 Child1 可以包含 func1() 和 func2() 但不包含 func3() 或 func4(),而 Child2 包含 func3() 和 func4() 但不包含 func1() 或 func2()?

所以 Child1 将包含:

int func1()
int func2()

而 Child2 将包含:

int func3()
int func4()

我问是因为我正在尝试做这样的事情,但是当我尝试运行它时,我不断收到未定义的引用错误。例如,会出现如下错误:

/tmp/cczUiDZ2.o:(.rodata._ZTV5Child1[_ZTV5Child1]+0x38): undefined reference to `Parent::func3()'

【问题讨论】:

  • 不——听起来你想要一个界面。
  • 什么是接口?
  • 如果您不希望它们被实际派生,为什么还要派生这些类?
  • @Jaclyn:考虑以下问题:Child1 child; Base* base = &child; base->func1(); base->func3(); 这两个方法调用实际上应该做什么?我们不能让它们在编译时失败。
  • 您可能需要重新考虑应用程序的架构。这些问题表明设计存在缺陷

标签: c++ inheritance


【解决方案1】:

假设您有一个具有多个功能的基类,例如

virtual int func1();
virtual int func2();
virtual int func3();
virtual int func4();

即使没有提及派生类,也已经存在潜在问题。你已经声明了Base::func1() 等等,但是你还没有定义这些函数。这就是链接器错误所抱怨的原因。

如果在基类级别定义这些函数没有意义,则需要通过在终止函数声明的分号之前插入 = 0 来将这些函数声明为“纯虚拟”:

class Base {
public:
  virtual int func1() = 0;
  virtual int func2() = 0;
  virtual int func3() = 0;
  virtual int func4() = 0;
  ...
};

(注意:我故意将那些纯虚函数公开。稍后我会谈到。)

这意味着这些函数可以在派生自基类的任何类上使用,但同时,在基类级别。如果这样做,则必须在子类(或子子类,或 sub-...-sub-child 类)中定义这些函数。具有未定义纯虚函数的类是不可实例化的。

如果您希望Child1 具有函数func1()func2(),但不具有func3()func4(),该怎么办?这些函数可以在基类级别调用,但不能在子类级别调用。这违反了Liskov substitution principle。这是一个很大的迹象,表明您的设计是错误的。

另一种方法是在基类级别(有意义的地方)提供默认实现,并在子类级别(有意义的地方)覆盖它们。您的Child1 可以提供func1()func2() 的特定类定义,这些定义覆盖基类中提供的默认值。

另一种选择是使用多重继承。多重继承会给你带来很大的麻烦,但如果做得对,多重继承并没有错。

另一种选择是做一些颠覆但不违反 Liskov 替换的事情。例如,在Child1 中实现func3()func4(),但在这些实现中总是抛出异常。不要这样做。

【讨论】:

    【解决方案2】:

    您无法实现您真正提出的要求,即一个子类没有“拥有”基类的功能,而另一个子类拥有它。但是,从您的示例中,我看到您的意思可能有所不同。我们看下面的例子:

    class Parent
    {
      virtual int func1() = 0;
      virtual int func2()
        { return 0; }
    };
    
    class Child: public Parent
    {
      int func1()
        { return 0; }
    };
    
    int main()
    {
      Child c;
    }
    

    在此示例中,类 Child 不会覆盖虚拟 func2。但是,您可以看到Parent 类提供了自己的定义,在这种情况下将用作“默认”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-24
      • 2011-09-17
      • 1970-01-01
      • 2020-07-14
      • 1970-01-01
      • 2013-08-25
      • 2011-11-23
      • 1970-01-01
      相关资源
      最近更新 更多