Можно ли переопределить функцию в дочернем классе C ++ без использования виртуального ключевого слова для функции в родительском классе, которая является абстрактной? - PullRequest
9 голосов
/ 08 марта 2012
class Parent {
public:
    void func1(); // Complete meaningful definition in parent given.

    virtual HRESULT func2()=0;  // Bcoz of this function Parent class is abstract. 
};


class Child: public Parent {
public:
    void func1(); // Different definition in child.
};

Возможно ли это в C ++?Я переопределяю func1(), который НЕ является виртуальным, и у него уже есть определение в родительском абстрактном классе.

Ответы [ 5 ]

21 голосов
/ 08 марта 2012

[при условии, что Child расширяется Parent, в отличие от того, что показывает снимок кода]

Да, это возможно [это называется скрытием] - но вы не получите динамическую диспетчеризацию поведения.

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

Например:

Parent* p = new Child;
p->func1();

Запустит Parent::func1()
, а

Child* c = new Child;
c->func1();

Запустит Child::func1()

6 голосов
/ 08 марта 2012

Нет, фактически невозможно переопределить определение в родительском (по крайней мере, когда речь идет о C ++, "переопределение" обычно зарезервировано специально для ссылки на виртуальные функции).Вместо этого, определяя функцию с тем же именем в дочернем классе, просто скрывает функцию в родительском объекте с тем же именем (т. Е. В контексте дочернего объекта, поиск этого имени найдет толькофункция в дочернем элементе, а не родительская).

Если вы хотите (и функции имеют разные подписи), вы также можете получить функции как в родительском, так и в дочернем элементах, обработанные как перегруженные, поэтомуcall будет пытаться вызывать любое совпадение лучше:

struct parent {
    void func1(char) {}
};

struct child : public parent { 
    void func1(long) { }

    using parent::func1;
};

Теперь вы получите:

child c;
c.func1('a'); // calls parent::func1
c.func1(123L); // calls child::func1

Это еще один третий тип поведения, отличающийся от наличия виртуальной функции или с функцией в дочернем элементе, которая скрывает функцию в родительском элементе.

В виртуальной функции выбор вызываемой функции основан на динамическом типе, поэтому если у вас есть указатель/ ссылка на базовый класс, вызываемая функция зависит от того, ссылается ли она на объект базового или производного класса.

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

С помощью оператора using вы получите функциюперегрузка, поэтому при вызове функции (в контексте производного класса) вызываемая функция зависит от того, какая сигнатура функции лучше всего подходит для передаваемого вами параметра (параметров).

3 голосов
/ 08 марта 2012

Вы можете перегрузить , если они имеют разные типы аргументов.

Вы можете скрыть это, в показанном здесь смысле, так что Child::func1 будет вызываться вместо Parent::func1 в коде, который знает, что смотрит на дочерний экземпляр. Однако, как указывает amit, вы не получаете динамическую отправку.


struct StaticParent {
  void foo();
};
struct StaticChild : public StaticParent {
  void foo();
}

StaticChild sc;
sc.foo(); // calls StaticChild::foo

StaticParent &sp = sc;
sp.foo(); // calls StaticParent::foo

struct VirtualParent {
  virtual void foo();
};
struct VirtualChild : public VirtualParent {
  virtual void foo();
}

VirtualChild vc;
vc.foo(); // calls VirtualChild::foo

VirtualParent &vp = vc;
vp.foo(); // calls VirtualChild::foo
0 голосов
/ 08 марта 2012

Большинство было сказано.

Ваши ожидания будут правильными, если вы говорите о Java.В Java любой не приватный, не финальный метод может быть переопределен.Возможно, вы более знакомы с языком программирования, отличным от C ++

Кстати, в вашем коде две вещи неправильные

  • " class " должно быть написанонижний регистр
  • доступ по умолчанию для членов класса: " private ".ЗАПРЕЩАЕТСЯ и бесполезно переопределять закрытые члены, которые не являются чистыми
0 голосов
/ 08 марта 2012

Да, это допустимый синтаксис C ++, и он определяет Child :: func1, который скрывает Parent :: func1 в Child.

Однако это не означает, что он полностью заменяет Child :: Parent :: func1. Эту функцию все еще можно вызывать явно для элемента child.

Child c;
c.Parent::func1();

Кроме того, эта функция не будет виртуальной. Таким образом, следующее ..

Child c;
Parent& p = c;
p.func1();

будет вызывать Parent :: func1, а не Child :: func1.

...