Что означает 0 в чистой виртуальной функции
Программа ниже не компилируется по понятным причинам:
#include <iostream>
using namespace std;
class A {
public:
A() { pVirt(); }
virtual void pVirt() const = 0 { count<<"A::pVirt()"; }
};
int main() {
A aObj;
aObj.pVirt();
reutrn 0;
}
Вопросы: 1. 0 в сигнатуре "virtual void pVirt() const = 0" означает что?, Это указывает на смещение памяти NULL в vtable или просто ограничение синтаксиса?
- Если 0 - это NULL смещение памяти (если это так), то почему VC++ не позволяет указывать другой адрес памяти, и именно поэтому мы не можем вызывать чисто виртуальную функцию извне конструктора (МОЖЕТ БЫТЬ, потому что vtable создан после того, как объект полностью построен.)?
4 ответа
0 в подписи "virtual void pVirt() const = 0" означает что?,
Часть =0
называется чисто-спецификатором. Это делает виртуальную функцию чистой, а класс абстрактным.
Чистая виртуальная функция не должна иметь определения. Вы можете при желании предоставить определение вне класса, и неабстрактный производный класс все еще должен переопределить функцию.
class A
{
public:
virtual ~A() {};
virtual void f() =0;
};
void A::f() { std::cout << "A::f" << std::endl; } //optional
Определение f
не делает класс неабстрактным, поэтому вы не можете создать экземпляр A
:
A a; //error - A is abstract
Кроме того, производный класс должен переопределить A::f
чтобы быть неабстрактным:
class B : public A {};
B b; //error : B is still an abstract class as it didn't override A::f
А также
class C : public A { void f() {} };
C c; //okay : C override A::f
И реализация производного класса может выбрать вызов реализации базового класса:
class D : public A { void f() { A::f(); } }; //defaults to A::f
D d; //okay : D override A::f, but calls A::f internally
Надеюсь, это поможет.
Это просто синтаксис для обозначения того, что функция является чисто виртуальной. Это не имеет никакого реального значения вообще. Дизайнеры C++ также могут быть выбраны для использования pure
или же abstract
на месте = 0
, Я подозреваю, что единственная причина этого не состояла в том, что они не хотели вводить новое зарезервированное слово в язык (поскольку это нарушает любой существующий код, который уже использует вновь зарезервированное слово в качестве идентификатора).
(Не нужно делать такое слово зарезервированным, так как это будет контекстно-зависимое ключевое слово, но концепция контекстно-зависимых ключевых слов только недавно вошла в массовое использование, и этот синтаксис намного старше.)
= 0
в объявлении функции просто синтаксис: последовательность из двух токенов означает, что функция чистая, вот и все. И вы не можете заменить ни один из токенов чем-либо еще: =
0L
не законно, например.
И причина, по которой вы получаете ошибку, заключается просто в том, что синтаксис не разрешен. По историческим причинам, если не больше. Если вы хотите предоставить определение для чисто виртуальной функции, вы должны сделать это вне класса.
И если вы предоставите определение для чисто виртуальной функции, вы можете вызвать ее из конструктора; вам просто нужно отключить механизм виртуального вызова; например A::pVirt()
, Если фактический вызов функции включает в себя динамическое разрешение, и разрешение приводит к чисто виртуальной функции, это неопределенное поведение, независимо от того, определена функция или нет. Мотивация здесь состоит в том, чтобы позволить вам не определять это; обычно виртуальная функция должна быть определена независимо от того, вызываете вы ее или нет, потому что компилятор должен поместить ее адрес в vtable
и, если он не определен, адрес отсутствует. Создание функции чисто виртуальной говорит компилятору, что она не должна помещать свой адрес в vtable
, Так что вам не нужно это определять. Но вы можете получить сюрпризы, если попытаетесь вызвать функцию через vtable.
= 0
после того, как виртуальная функция означает, что "это чисто виртуальная функция, она должна быть реализована в производной функции". Как и в вашем примере, все еще возможно реализовать функцию. У него нет другого значения как такового - и вы не можете использовать другие номера, адреса или что-то еще. Вы можете иметь несколько функций с =0
и это все равно будет иметь тот же смысл.