Абстрактный класс с чисто виртуальным методом - почему можно сделать «Abstract * abs3;»? - PullRequest
4 голосов
/ 01 сентября 2011

Рассмотрим следующее:

class Abstract
{
public:
    virtual void func() = 0;
};

int main() {

    Abstract abs1; // doesn't compile
    Abstract * abs2 = new Abstract(); // doesn't compile
    Abstract * abs3;  // compiles

    return 0;
}

Обратите внимание, что я не реализовал func(), так почему можно сделать Abstract * abs3; где у нас есть чистый виртуальный метод и абстрактный класс? Я знаю, что я получу ошибку во время выполнения, если я попытаюсь сделать abs3-> func (); , но все же мне не понятно, почему C ++ позволяет компилировать этот код ...?

спасибо, Рон

Ответы [ 6 ]

7 голосов
/ 01 сентября 2011

abs3 - указатель на класс. Его можно инициализировать для любого конкретного подкласса Abstract или NULL, безопасно. Компилятор должен разрешить это, потому что, хотя вы не можете создавать абстрактные классы, вы должны иметь возможность создавать указатели на них. Ниже приведен пример

class Concrete: public Abstract
{
public:
    virtual void func() { // do something };
};


int main ()
{
   Abstract* abs3 = NULL;
   abs3 = new Concrete;
}
4 голосов
/ 01 сентября 2011

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

3 голосов
/ 01 сентября 2011

Короткий ответ

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

Длинный ответ

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

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

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

РЕДАКТИРОВАТЬ:
Даже если вы предоставляете определение чисто виртуальной функции (и это совершенно правильно сделать), вы все равно не можете создать экземпляр класса Abstract, потому что в тот момент, когда вы объявляетеФункция как чисто виртуальная, компилятор рассматривает класс как абстрактный (Incomplete), и он больше не может быть создан.

1 голос
/ 01 сентября 2011

Наследование - это ключевая идея, которую вам не хватает.Если Vehicle является абстрактным, а Car является транспортным средством, тогда Vehicle* является совершенно допустимым типом для указателя на экземплярный экземпляр Car.Абстрактный базовый класс является допустимым типом в качестве аргумента метода (ссылки), и независимо от того, передан ли Car или Bike, будет вызвана правильная виртуальная реализация func.Это ключевая особенность языка.

1 голос
/ 01 сентября 2011

На самом деле, смысл в том, чтобы иметь возможность создать указатель на абстрактный класс, состоит в том, чтобы указывать на (конкретные) классы, производные от абстрактного класса:

class Abstract
{
public:
    virtual void func() = 0;
};

class Derived1 : public Abstract
{
public:
    virtual void func() { /* do something */ }
}

class Derived2 : public Abstract
{
public:
    virtual void func() { /* do something else */ }
}

, а затем, например:

Abstract * ap;

if (/*something*/)
    ap = new Derived1();
else
    ap = new Derived2();

ap->func();
delete ap;
0 голосов
/ 01 сентября 2011

Вы просто не можете иметь экземпляр класса, где один или несколько методов не были реализованы.

То, что вы пытаетесь сделать здесь, это наличие экземпляров класса, который имеет чистый абстрактный метод с именем func(): это невозможно.

Abstract * abs3

компилируется как неинициализированный указатель, там вы не выделяете ни одного экземпляра Abstract.

Abstract abs1;
Abstract * abs2 = new Abstract();

никогда не скомпилируется. Вы должны указать Abstract (через наследование), обеспечивающий реализацию для func(), и в этот момент вы сможете иметь экземпляры такого производного класса.

...