Каково влияние переопределения (обычного) виртуального метода чисто виртуальным методом? - PullRequest
3 голосов
/ 27 января 2009

Допустим, у нас есть

class A {    
public:    
    virtual int foo() { cout << "foo!"; }    
}

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

class C : public B {
public:
    virtual int foo() { cout << "moo!"; }
}

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

Мы получили базовый класс A. Затем мы получили абстрактный производный класс B, производный от конкретного класса A, а затем реализацию B через C.

Что мы здесь делаем, и имеет ли это какой-то смысл?

Ответы [ 4 ]

3 голосов
/ 27 января 2009

Перегрузка будет означать, что у вас есть две функции с одним и тем же именем, но с разными параметрами. Здесь дело не в этом.

Пример:

int functionA() { /*...*/ };
int functionA(int someParameter) { /*...*/ };

Переопределение означает переписывание функции с теми же параметрами в подклассе. Это то, что вы привели в качестве примера.

Это часть определения. Теперь о дизайне:

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

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

1 голос
/ 27 января 2009

Вы говорите, что классы, производные от B, должны реализовывать int foo (); . Возможно, вы захотите сделать что-то подобное, чтобы заставить других программистов задуматься о том, как они хотят, чтобы foo () вел себя, но я думаю, что это плохая идея - в действительности они могут реализовать это, вызвав A :: Foo () .

Если вы просто хотите сделать B абстрактным, предоставьте ему чистый виртуальный деструктор - вам также потребуется обеспечить реализацию деструктора, чтобы избежать ошибки ссылки.

1 голос
/ 27 января 2009

Это все еще переопределение, потому что когда у вас есть указатель p типа A* на экземпляр класса C, p->foo() все еще вызывает C::foo()

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

1 голос
/ 27 января 2009

Мне кажется, что единственный эффект чисто виртуального метода здесь - сделать B абстрактным классом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...