2013-07-02 3 views
3

Класс, содержащий чистую виртуальную функцию, не может иметь объект. Это была моя идея о чистых виртуальных функциях. У меня есть следующая программа, и она скомпилирована без ошибок.Многоуровневое наследование и чистые виртуальные функции

#include<iostream> 

using namespace std; 

class Father { 
    public: 
    virtual void foo()=0; 
}; 

class Son:public Father { 
    // Nothing here 
}; 

int main() { 

} 

Ожидалось, что оба класса не имеют объекта. Но следующая программа давала мне ошибки, когда я пытался иметь многоуровневое наследование от класса, содержащего чистую виртуальную функцию.

#include<iostream> 

using namespace std; 

class Father { 
    public: 
    virtual void foo()=0; 
}; 

class Son:public Father { 
    // Nothing here 
}; 

class Grand_Son:public Son { 
    void foo() { 
     cout<<"\nFunction foo From Grand_Son\n"; 
    } 
}; 

int main() { 
    Grand_Son x; 
    x.foo(); 
} 

Ошибки показаны ниже.

In function 'int main()':| 
|error: 'virtual void Grand_Son::foo()' is private| 
|error: within this context| 
||=== Build finished: 2 errors, 0 warnings ===| 

Ошибки были неожиданными, поскольку я унаследовал классы Son и Grand_Son в public.

Возможно ли иметь многоуровневое наследование классами, включающими чистые виртуальные функции?

Любые предложения? Спасибо.

+1

Если что-то считается приватным, проверьте, действительно ли он находится в общедоступной части вашего класса. Он является общедоступным в вашем базовом классе, но не в 'Grand_Son'. – Zeta

+3

Самое смешное, что при использовании 'Father * x = new Grand_Son; x-> foo(); ', было бы хорошо, потому что теперь через foo() открывается через Father, где он является общедоступным. Это можно использовать для обеспечения того, чтобы foo использовался только через полиморфизм. – stefaanv

ответ

7
class Grand_Son:public Son { 
    public: 
---^^^^^^^ 
    void foo() { 
     cout<<"\nFunction foo From Grand_Son\n"; 
    } 
}; 

Вы не объявили foo общественностью - я добавил его выше.

6

Вы foo() в частном разделе Grand_Son

доступа по умолчанию в class в С ++ private, который не имеет ничего общего с тем, как вы унаследовали (государственные/частные/защищенные/по умолчанию).

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

class Grand_Son:public Son { 
    public: <------- This will fix your compiler problem. 
    void foo() { 
     cout<<"\nFunction foo From Grand_Son\n"; 
    } 
}; 

ИЛИ это должно работать, потому что вы будете использовать класс полиморфны на базовый класс, который будет совершать поиск v-таблицу на основе уровня доступа в базовом классе. Вы должны соответствовать вашим уровням доступа, хотя по всей иерархии.

int main() { 
    Father* x = new Grand_Son(); 
    x->foo(); 
} 
4

Вы должны объявить выполнение Foo() в Grand_Son в public.

3

Это совершенно не связано. Вы должны объявить свою foo() функцию в своем Grand_Son классе после заявления public:.

По умолчанию (т. Е. Без квалификаторов видимости) члены класса являются частными, поэтому ваш компилятор сообщает вам, что вы не можете получить доступ к функции-члену, поскольку она имеет видимость.

1

Основание на стандартной class.access.virt

доступа проверяется в точке вызова, используя тип выражения используется для обозначения объекта, для которого функция memeber называется. доступ к функции memeber в классе, в котором он был определен, вообще не знает.

Это означает, что в вашем примере он будет использовать Grand_Son, чтобы проверить доступность memeber. Поскольку вы не определяете участника как общедоступный, он будет закрытым (член класса по умолчанию является закрытым). Он не имеет отношения к публичному унаследованию.

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

Смежные вопросы