Как вызвать функцию родительского класса из производной функции класса?

Как мне вызвать родительскую функцию из производного класса, используя C ++? Например, у меня есть класс с именем parentи класс, childкоторый является производным от parent. Внутри каждого класса есть printфункция. В определении функции печати ребенка я хотел бы вызвать функцию печати родителей. Как бы я поступил так?

10.12.2008 19:35:45
Все вышеприведенные решения предполагают, что ваша функция печати является статическим методом. Это тот случай? Если метод не является статичным, то приведенные выше решения не актуальны.
hhafez 11.12.2008 10:51:39
hhafez, вы ошибаетесь, синтаксис base :: function () выглядит как статический синтаксис вызова метода, но он работает для методов экземпляра в этом контексте.
Motti 13.12.2008 18:59:34
Я бы не стал использовать MSVC __super, поскольку он зависит от платформы. Хотя ваш код может не работать на любой другой платформе, я бы воспользовался другими советами, поскольку они делают это так, как предполагалось.
Teaser 13.10.2010 23:39:30
Антипаттерном, где производные классы всегда требуются для вызова функций родительского класса, является Call super
Rufus 5.03.2019 03:43:24
7 ОТВЕТОВ
РЕШЕНИЕ

Я рискну заявить об очевидном: вы вызываете функцию, если она определена в базовом классе, она автоматически доступна в производном классе (если это не так private).

Если в производном классе есть функция с такой же сигнатурой, вы можете устранить ее неоднозначность, добавив имя базового класса, за которым следуют две двоеточия base_class::foo(...). Следует отметить, что в отличие от Java и C #, C ++ не имеет ключевого слова для «базового класса» ( superили base), поскольку C ++ поддерживает множественное наследование, что может привести к неоднозначности.

class left {
public:
    void foo();
};

class right {
public:
    void foo();
};

class bottom : public left, public right {
public:
    void foo()
    {
        //base::foo();// ambiguous
        left::foo();
        right::foo();

        // and when foo() is not called for 'this':
        bottom b;
        b.left::foo();  // calls b.foo() from 'left'
        b.right::foo();  // call b.foo() from 'right'
    }
};

Между прочим, вы не можете наследовать напрямую от одного и того же класса дважды, так как не будет никакого способа сослаться на один из базовых классов поверх другого.

class bottom : public left, public left { // Illegal
};
759
11.01.2017 09:48:20
Почему вы хотели бы наследовать от одного и того же класса дважды?
Paul Brewczynski 5.10.2013 18:39:11
@bluesm: в классическом ООП это не имеет особого смысла, но в универсальном программировании template<class A, class B> class C: public A, public B {};два типа могут быть одинаковыми по причинам, зависящим от того, как используется ваш код (что делает А и В одинаковыми), может быть два или три слой абстракции от кого-то, кто не знает, что ты сделал.
Emilio Garavaglia 18.11.2013 18:37:38
Я думаю , что это полезно добавить, что это будет вызывать родительский метод класса , даже если она не реализуется непосредственно в родительском классе, но будет реализован в одном из родительских классов в цепочке наследования.
Maxim Lavrov 26.12.2014 10:30:33
На sidenote, я разозлился, когда я попытался поместить это в файл cpp. Я использовал 'namespace std'. 'left' определяется где-то в этом пространстве имен. Пример не скомпилируется - сводил меня с ума :). Затем я изменил «левый» на «левый». Отличный пример, кстати.
Mathai 27.08.2015 20:36:44
@ Mathai И вот почему вы не должны использовать using namespace std.
JAB 8.10.2015 21:06:19

Учитывая родительский класс named Parentи дочерний класс named Child, вы можете сделать что-то вроде этого:

class Parent {
public:
    virtual void print(int x);
}

class Child : public Parent {
    void print(int x) override;
}

void Parent::print(int x) {
    // some default behavior
}

void Child::print(int x) {
    // use Parent's print method; implicitly passes 'this' to Parent::print
    Parent::print(x);
}

Обратите внимание, что Parentэто фактическое имя класса, а не ключевое слово.

192
26.02.2019 19:26:10
Конечно, это было бы полезно только в том случае, если базовый вызов перемежался с другой логикой, иначе не было бы смысла переопределять функцию, так что, может быть, это немного слишком к месту;)
underscore_d 11.04.2016 13:20:02
@underscore_d на самом деле, это полезно, даже если базовый вызов не перемежался с другой логикой. Допустим, родительский класс в значительной степени делает все, что вы хотите, но предоставляет метод foo (), который вы не хотите, чтобы пользователи child использовали, - либо потому, что foo () не имеет смысла для дочерних элементов, либо внешние вызывающие элементы для child будут испорчены, что такое child. делает. Таким образом, child может использовать parent :: foo () в определенных ситуациях, но предоставить реализацию foo, чтобы скрыть родительский foo () от вызова.
iheanyi 22.04.2016 18:56:27
@iheanyi Звучит интересно, но извините, я еще не понимаю этого. Есть foo()здесь аналогична print()или отдельной функции? И вы имеете в виду, используя privateнаследование, чтобы скрыть детали, унаследованные от базы, и предоставляя publicфункции теневого копирования для вещей, которые вы хотите показать?
underscore_d 22.04.2016 19:02:58
@underscore_d Да, foo()было аналогично print(). Позвольте мне вернуться к использованию, так print()как я думаю, что это будет иметь больше смысла в этом контексте. Допустим, кто-то создал класс, который выполнил некоторый набор операций с определенным типом данных, открыл некоторые print(obj&)методы доступа и имел метод. Мне нужен новый класс, который работает, array-of-objно все остальное то же самое. Композиция приводит к большому количеству дублированного кода. Наследование сводит это к минимуму при print(array-of-obj&) вызове цикла print(obj&), но не хочет, чтобы клиенты звонили, print(obj&)потому что для них это не имеет смысла
iheanyi 25.04.2016 15:34:59
@underscore_d Это основано на предположении, что я не могу реорганизовать общие части исходного родительского класса или что это невероятно дорого. Частное наследование может сработать, но тогда вы потеряете общедоступные средства доступа, на которые вы полагались, и, следовательно, должны будут дублировать код.
iheanyi 25.04.2016 15:37:09

Если ваш базовый класс вызывается Base, а ваша функция вызывается, FooBar()вы можете вызвать его напрямую, используяBase::FooBar()

void Base::FooBar()
{
   printf("in Base\n");
}

void ChildOfBase::FooBar()
{
  Base::FooBar();
}
32
31.05.2015 20:21:01

В MSVC для этого есть специальное ключевое слово Microsoft: __super


MSDN: позволяет явно указать, что вы вызываете реализацию базового класса для функции, которую вы переопределяете.

// deriv_super.cpp
// compile with: /c
struct B1 {
   void mf(int) {}
};

struct B2 {
   void mf(short) {}

   void mf(char) {}
};

struct D : B1, B2 {
   void mf(short) {
      __super::mf(1);   // Calls B1::mf(int)
      __super::mf('s');   // Calls B2::mf(char)
   }
};

28
26.05.2009 18:51:57
Эх, я бы предпочел, typdefчтобы родитель был чем-то вроде super.
Thomas Eding 1.11.2011 19:06:43
Я не буду пытаться оправдать использование __super; Я упомянул это здесь как альтернативное предложение. Разработчики должны знать свой компилятор и понимать плюсы и минусы его возможностей.
Andrey 30.01.2012 01:56:58
Я предпочел бы отговорить кого-либо от его использования, поскольку это сильно затрудняет переносимость кода.
Erbureth says Reinstate Monica 13.03.2014 13:42:24
Я не согласен с Андреем: разработчики должны знать стандарт и не должны беспокоиться о функциях компилятора, если мы рассматриваем написание программного обеспечения, которое в первую очередь не зависит от компилятора, что я считаю хорошей идеей, так как рано или поздно в больших проектах многокомпиляторов в любом случае используются.
Gabriel 11.12.2014 17:39:47
«Разработчики должны знать свой компилятор», именно из-за этого и включения нестандартных функций IE6 ...
Ring Ø 4.08.2016 10:50:30
struct a{
 int x;

 struct son{
  a* _parent;
  void test(){
   _parent->x=1; //success
  }
 }_son;

 }_a;

int main(){
 _a._son._parent=&_a;
 _a._son.test();
}

Справочный пример.

-15
2.06.2014 14:07:17
Не могли бы вы отредактировать объяснение, почему / как этот код отвечает на вопрос? Ответы только на код не приветствуются, потому что их не так легко выучить, как код с объяснением. Без объяснения требуется гораздо больше времени и усилий, чтобы понять, что было сделано, изменения, внесенные в код, или, если код полезен. Это объяснение важно как для людей, пытающихся извлечь уроки из ответа, так и для тех, кто оценивает ответ, чтобы понять, является ли он действительным или стоит голосовать.
Makyen 23.02.2015 05:30:27
Этот ответ касается вложенных классов, в то время как вопрос касался производных классов (хотя слова 'parent' и 'child' немного вводят в заблуждение) и поэтому вообще не отвечает на вопрос.
Johannes Matokic 5.08.2015 07:54:10

Если модификатор доступа к функции-члену базового класса защищен ИЛИ общедоступен, вы можете вызвать функцию-член базового класса из производного класса. Можно вызвать не виртуальную и виртуальную функцию-член базового класса из производной функции-члена. Пожалуйста, обратитесь к программе.

#include<iostream>
using namespace std;

class Parent
{
  protected:
    virtual void fun(int i)
    {
      cout<<"Parent::fun functionality write here"<<endl;
    }
    void fun1(int i)
    {
      cout<<"Parent::fun1 functionality write here"<<endl;
    }
    void fun2()
    {

      cout<<"Parent::fun3 functionality write here"<<endl;
    }

};

class Child:public Parent
{
  public:
    virtual void fun(int i)
    {
      cout<<"Child::fun partial functionality write here"<<endl;
      Parent::fun(++i);
      Parent::fun2();
    }
    void fun1(int i)
    {
      cout<<"Child::fun1 partial functionality write here"<<endl;
      Parent::fun1(++i);
    }

};
int main()
{
   Child d1;
   d1.fun(1);
   d1.fun1(2);
   return 0;
}

Вывод:

$ g++ base_function_call_from_derived.cpp
$ ./a.out 
Child::fun partial functionality write here
Parent::fun functionality write here
Parent::fun3 functionality write here
Child::fun1 partial functionality write here
Parent::fun1 functionality write here
5
25.12.2015 11:16:51
Спасибо, что привели несколько примеров с virtual!
M.Ioan 5.04.2020 21:06:23

Вызовите родительский метод с оператором разрешения родительской области.

Родитель :: Способ ()

class Primate {
public:
    void whatAmI(){
        cout << "I am of Primate order";
    }
};

class Human : public Primate{
public:
    void whatAmI(){
        cout << "I am of Human species";
    }
    void whatIsMyOrder(){
        Primate::whatAmI(); // <-- SCOPE RESOLUTION OPERATOR
    }
};
4
4.05.2019 21:50:50