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

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

Все приведенные выше решения предполагают, что ваша функция печати является статическим методом. Так ли это? Если метод не является статическим, то приведенные выше решения не актуальны.

hhafez 11.12.2008 13:51

hhafez, вы ошибаетесь, синтаксис base :: function () выглядит как синтаксис вызова статического метода, но он работает для методов экземпляра в этом контексте.

Motti 13.12.2008 21:59

Я бы не стал использовать MSVC __super, поскольку он зависит от платформы. Хотя ваш код может не работать на какой-либо другой платформе, я бы использовал другие предложения, поскольку они делают это в соответствии с предназначенным языком.

Teaser 14.10.2010 03:39

Антипаттерн, в котором производные классы всегда требуется для вызова функций родительского класса, - Звоните супер

Rufus 05.03.2019 06:43
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
647
5
714 373
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Учитывая родительский класс с именем Parent и дочерний класс с именем 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 - это настоящее имя класса, а не ключевое слово.

Конечно, это было бы полезно только в том случае, если бы базовый вызов был перемежен с другой логикой, иначе не было бы смысла переопределять функцию, так что, возможно, это немного тоже по существу;)

underscore_d 11.04.2016 16:20

@underscore_d на самом деле, это полезно, даже если базовый вызов не перемежается с другой логикой. Скажем, родительский класс в значительной степени делает все, что вы хотите, но предоставляет метод foo (), который вы не хотите, чтобы пользователи дочернего элемента использовали - либо потому, что foo () не имеет смысла для дочернего элемента, либо внешние вызывающие его дочерние объекты испортят то, что дочерний делает. Таким образом, дочерний элемент может использовать parent :: foo () в определенных ситуациях, но предоставить реализацию foo, чтобы скрыть родительский foo () от вызова.

iheanyi 22.04.2016 21:56

@iheanyi Звучит интересно, но извините, я еще не понял. foo() здесь аналог print() или отдельная функция? И вы имеете в виду использование наследования private, чтобы скрыть детали, унаследованные от базы, и предоставление функций затенения public для вещей, которые вы делать хотите раскрыть?

underscore_d 22.04.2016 22:02

@underscore_d Да, foo() был аналогом print(). Позвольте мне вернуться к использованию print(), поскольку я думаю, что это будет иметь больше смысла в этом контексте. Допустим, кто-то создал класс, который выполняет некоторый набор операций с определенным типом данных, предоставляет некоторые средства доступа и имеет метод print(obj&). Мне нужен новый класс, который работает на array-of-obj, но все остальное то же самое. Композиция приводит к дублированию кода. Наследование минимизирует это в цикле print(array-of-obj&), вызывающем print(obj&), но не хочет, чтобы клиенты вызывали print(obj&), потому что для них это не имеет смысла.

iheanyi 25.04.2016 18:34

@underscore_d Это основано на предположении, что я не могу реорганизовать общие части исходного родительского класса или что это невероятно дорого. Частное наследование может работать, но тогда вы потеряете общедоступные методы доступа, на которые вы полагались, и, следовательно, вам потребуется дублировать код.

iheanyi 25.04.2016 18:37

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

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

void ChildOfBase::FooBar()
{
  Base::FooBar();
}
Ответ принят как подходящий

Я рискну заявить очевидное: вы вызываете функцию, если она определена в базовом классе, она автоматически доступна в производном классе (если это не 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
};

Почему вы хотите наследовать один и тот же класс дважды?

Paul Brewczynski 05.10.2013 22:39

@bluesm: в классическом ООП это не имеет особого смысла, но в универсальном программировании template<class A, class B> class C: public A, public B {}; может иметь два одинаковых типа по причинам, зависящим от того, как используется ваш код (что делает A и B одинаковыми), может быть два или три уровня абстракции от кого-то, кто не знает, что вы сделали.

Emilio Garavaglia 18.11.2013 22:37

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

Maxim Lavrov 26.12.2014 13:30

что, если родительский метод использует это?

martinkunev 16.06.2015 17:28

@martinkunev, если базовый класс использует это, то он работает нормально для обычных методов и подавляет динамический вызов методов virtual.

Motti 16.06.2015 17:35

Кстати, я разозлился, когда попытался поместить это в файл cpp. У меня было использование пространства имен std. "left" определено где-то в этом пространстве имен. Пример не компилировался - сводил меня с ума :). Затем я изменил «левый» на «левый». Кстати, отличный пример.

Mathai 27.08.2015 23:36

@Mathai Вот почему вы не должны использовать using namespace std.

JAB 09.10.2015 00:06

+1 за указание You should note that unlike Java and C#, C++ does not have a keyword for "the base class".

TechNyquist 16.09.2016 11:15

Вы можете добавить typedef left super; в свой класс, если хотите, тогда вы можете обратиться к super::foo();. И поскольку вы не можете дважды наследовать один и тот же класс напрямую, вам придется делать это косвенно struct left1 : left{}; struct left2 : left{}; class bottom : public left1, public left2 { ... };, но вам, вероятно, лучше использовать композицию, а не наследование.

Eljay 29.09.2017 15:39

что произойдет, если foo будет виртуальной функцией в обоих базовых классах?

lsrawat 21.01.2019 18:39

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


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)
   }
};

Эх, я бы предпочел, чтобы typdef использовал родительский элемент как что-то вроде super.

Thomas Eding 01.11.2011 23:06

Я не буду оправдывать использование __super; Я упомянул это здесь как альтернативное предложение. Разработчики должны знать свой компилятор и понимать плюсы и минусы его возможностей.

Andrey 30.01.2012 05:56

Я бы предпочел отговорить кого-либо от его использования, поскольку это серьезно затрудняет переносимость кода.

Erbureth says Reinstate Monica 13.03.2014 17:42

Я не согласен с Андреем: разработчики должны знать стандарт и не должны беспокоиться о функциях компилятора, если мы рассматриваем возможность написания программного обеспечения, которое в основном не зависит от компилятора, что, на мой взгляд, в любом случае является хорошей идеей, потому что рано или поздно в больших проектах несколько компиляторов в любом случае используются.

Gabriel 11.12.2014 20:39

@ThomasEding Я бы не предпочел ни того, ни другого, потому что C++ - это не Java, и на самом деле нетрудно запомнить имя родителя, плюс это требуется при использовании MI.

underscore_d 11.04.2016 16:21
«Разработчики должны знать свой компилятор» это рассуждение и включение нестандартных функций привело к IE6 ...
e2-e4 04.08.2016 13:50

Это действительно плохая идея, всегда старайтесь избегать специфических функций компилятора, или они действительно необходимы, используйте их внутри #defines, где вы можете справиться стандартным и нестандартным способом.

Patricio Rossi 02.06.2017 05:30

Я собираюсь пойти против комментариев и проголосовать за __super. Это красиво и просто, и для 99,9% кода, который является SANE и не использует множественное наследование, с этим нет проблем. Явное указание базового класса привело к множеству трудно диагностируемых ужасных ошибок в нашей кодовой базе на протяжении многих лет, когда люди в конечном итоге случайно переходят прямо с Level3-> Level1 и пропускают класс Level2 посередине; __super предотвращает это. Также переносимый код, это хороший момент, однако не весь код заботится о переносимости.

Orion Edwards 23.08.2017 07:39

@OrionEdwards именно для этого кода с одним наследованием __super не добавляет функциональности, потому что вы можете явно назвать этот класс (или получить привычку делать typedef Parent super сразу после объявления класса, если вы хотите написать super): его основная цель - отправить вызов функции одного из двух суперклассов, когда метод может быть в том или ином (например, сценарий микширования). Жертва соответствия стандартам может быть оправдана, если вам явно нужна эта функциональность, а не из-за лени.

pqnet 12.03.2018 14:20

@OrionEdwards, хорошо, всегда вызывайте методы Level2 из Level3, и все будет в порядке

Alexey Andronov 16.05.2018 06:32
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();
}

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

Не могли бы вы объяснить редактировать, почему / как этот код отвечает на вопрос? Ответы, состоящие только из кода, не приветствуются, потому что на них не так легко научиться, как на коде с объяснением. Без объяснения требуется значительно больше времени и усилий, чтобы понять, что было сделано, какие изменения были внесены в код или полезен ли код. Объяснение важно как для людей, пытающихся извлечь уроки из ответа, так и для тех, кто оценивает ответ, чтобы увидеть, действителен ли он или стоит ли голосовать.

Makyen 23.02.2015 08:30

Этот ответ касается вложенных классов, в то время как вопрос касался производных классов (хотя слова «родительский» и «дочерний» немного ошибочны) и, следовательно, не отвечает на вопрос вообще.

Johannes Matokic 05.08.2015 10:54

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

#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

Спасибо, что принесли несколько примеров с virtual!

M.Ionut 06.04.2020 00:06

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

Parent::method()

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
    }
};

Другие вопросы по теме