Ваш класс B не переопределения функции члена в А, это перегрузках его. Или, во всяком случае, старайтесь, см. Бит о скрытии позже.
Overriding - это когда производный класс определяет собственную версию виртуальной функции-члена из базового класса. Перегрузка - это когда вы определяете разные функции с тем же именем.
Когда виртуальный вызов выполняется по указателю или ссылке, имеющей тип базового класса, он будет только «рассматривать» переопределения в производном классе, а не в перегрузках. Это важно - для того, чтобы экземпляр B обрабатывался вызывающими программами, как будто он делает все, что может сделать A (что является точкой динамического полиморфизма и виртуальных функций), его функция hello
должна иметь возможность принимать любой объект типа A Функция hello
, которая принимает объекты типа B, а не любые A, является более ограничительной. Он не может играть роль функции A hello
, поэтому это не переопределение.
Если вы немного экспериментируете с вызовом hello
на A и B, передавая объекты типа A или B, вы должны иметь возможность увидеть разницу. A имеет функцию, принимающую A (которую вы не определили, поэтому, если вы ее назовете, ваша программа не сможет ссылаться, но вы можете это исправить). B имеет функцию, берущую B. Они имеют одно и то же имя, и, разумеется, поскольку B происходит от A, вы можете передать B в функцию, берущую функцию A. Но B не действует как переопределение в виртуальных вызовах ,
Функцию A можно использовать для объекта B, но только через ссылку или указатель на A. Особенность C++ заключается в том, что определение hello
в B скрывает определение в A. Если перегрузка - это то, что вы хотите , можно отменить функцию базового класса, добавив using A::hello;
в класс B. Если переопределение - это то, что вы хотите, вы должны определить функцию, принимающую те же параметры. Например:
#include <iostream>
class A
{
public:
virtual int hello(A a) {std::cout << "A\n"; }
virtual int foo(int i) { std::cout << "A::Foo " << i << "\n"; }
};
class B : public A
{
public:
using A::hello;
// here's an overload
int hello(B b){ std::cout << "B\n"; };
// here's an override:
virtual int foo(int i) { std::cout << "B::Foo " << i << "\n"; }
};
int main() {
A a;
B b;
a.hello(a); // calls the function exactly as defined in A
a.hello(b); // B "is an" A, so this is allowed and slices the parameter
b.hello(a); // OK, but only because of `using`
b.hello(b); // calls the function exactly as defined in B
A &ab = b; // a reference to a B object, but as an A
ab.hello(a); // calls the function in A
ab.hello(b); // *also* calls the function in A, proving B has not overridden it
a.foo(1); // calls the function in A
b.foo(2); // calls the function in B
ab.foo(3); // calls the function in B, because it is overridden
}
Выход:
A
A
A
B
A
A
A::Foo 1
B::Foo 2
B::Foo 3
Если Вы убираете using A::hello;
линию от B, то вызов b.hello(a);
не удается скомпилировать:
error: no matching function for call to `B::hello(A&)'
note: candidates are: int B::hello(B)
Обратите внимание, что оператор 'new' возвращает указатель, поэтому' A a = new B; 'не соответствует правилу. Вы хотите либо «A a = B();», либо «A * a = new B();», хотя каждый делает разные вещи. Одно большое отличие - это бывшие фрагменты B (http://en.wikipedia.org/wiki/Object_slicing). Если A абстрактно, то только последнее является законным. – outis
Чтобы иметь чистый виртуальный базовый класс, по крайней мере одна функция должна быть определена следующим образом: virtual int hello (A a) = 0; и все классы, полученные из этого базового класса mush, перезаписывают эту функцию. Вы не можете создать объект чистого виртуального базового класса. – TheFuzz