Интересная абстрактная функция C ++ - PullRequest
3 голосов
/ 13 декабря 2008

почему это происходит?

Когда вы создаете абстрактный класс в C ++ Пример: Класс A (который имеет чисто виртуальную функцию) после этого класс B наследуется от класса A

И если класс A имеет конструктор с именем A () предположим, что я создал Object из класса B , затем компилятор сначала инициализирует базовый класс, т. е. class A , а затем инициализирует класс B Затем .......

Во-первых, мы не можем получить доступ к конструктору какого-либо класса без объекта, тогда как он инициализирует конструктор абстрактного класса, если мы не можем создать объект абстрактного класса.

Ответы [ 5 ]

8 голосов
/ 13 декабря 2008

Быстрый ответ: конструкторы особые.

Когда конструктор A все еще работает, тогда конструируемый объект еще не относится к типу A. Он все еще создается. Когда конструктор завершает работу, это теперь A.

То же самое для производного B. Конструктор для A запускается первым. Теперь это A. Затем конструктор для B начинает работать. Во время этого объект все еще действительно является A. Только после завершения конструктора B он становится B.

Вы можете убедиться в этом, попытавшись вызвать чисто виртуальную функцию из конструкторов. Если функция определена в A, и конструктор B вызывает ее, будет возникать ошибка во время выполнения вместо выполнения переопределения B, поскольку объект еще не имеет тип B.

Компилятор не позволит вам сгенерировать код, который будет создавать A из-за чисто виртуальной функции. Но он сгенерирует код для конструирования A как часть процесса построения B. В этом нет никакой магии. Правило, что вы не можете построить А, навязывается правилами языка, а не физикой. Язык отменяет это правило при особых обстоятельствах конструирования объектов Б.

4 голосов
/ 13 декабря 2008

class A абстрактно, а class B нет. Чтобы создать class B, он должен реализовать все чисто виртуальные функции-члены class A.

class A
{
public:
    A() {}
    virtual ~A() {}
    virtual void foo() = 0; // pure virtual
    int i;
};


class B : public A
{
public:
    B() {}
    virtual ~B() {}
    virtual void foo() {}
    int j;
};

Макет класса A может выглядеть примерно так:

+---------+     +---------+
| vftable | --> | ~A()    | --> address of A::~A()
+---------+     +---------+
| i       |     | foo()   | --> NULL, pure virtual
+---------+     +---------+

Макет класса B может выглядеть примерно так:

+---------+     +---------+
| vftable | --> | ~B()    | --> address of B::~B()
+---------+     +---------+
| i       |     | foo()   | --> address of B::foo()
+---------+     +---------+
| j       |
+---------+
1 голос
/ 13 декабря 2008
struct A {
  A(int x) {..}
  virtual void do() = 0;
};

struct B : public A {
   B() : A(13) {}      // <--- there you see how we give params to A c'tor
   virtual void do() {..}
};
0 голосов
/ 13 декабря 2008

То, что вы не можете создать экземпляр класса A напрямую, не означает, что создать экземпляр класса A невозможно. Вам не разрешено создавать экземпляр A, потому что компилятор знает, что A является абстрактным, и отклоняет любой написанный вами код, который пытается напрямую создать экземпляр A. Это запрещает код, подобный этому:

A a;
new A();

Что делает класс абстрактным, так это то, что он имеет чисто виртуальные методы. Тем не менее, ничто не мешает созданию такого класса. Стандарт C ++ просто говорит, что это запрещено. Компилятор вполне способен генерировать инструкции для создания экземпляра абстрактного класса. Все, что ему нужно сделать, - зарезервировать нужное количество памяти и затем вызвать конструктор, так же, как это было бы для неабстрактного класса.

Когда вы создаете экземпляр B, вся память для класса выделяется сразу. Поскольку все байты есть, там, по сути, есть экземпляр A, готовый для инициализации конструктором. (Но обратите внимание, что память формально не считается объектом типа A до тех пор, пока после не завершится работа конструктора A.) Запустится конструктор A, а затем конструктор B пробеги.

0 голосов
/ 13 декабря 2008
 And if class A has constructor called A() suppose i created an
 Object of class B then the compiler initializes the base class
 first i.e.class A and then initialize the class B
 Then.......?

На самом деле вы ошиблись:

Когда вы создаете объект класса B, вызывается конструктор B.
Если вы не укажете, как конструктор B вызывает конструктор A, то компилятор автоматически вставит в качестве первого действия в списке инициализатора вызов конструктора по умолчанию A.

Если вы не хотите использовать конструктор по умолчанию, вы должны явно поместить вызов соответствующего конструктора A в качестве первого элемента в списке инициализатора.

Когда строительство A будет завершено, строительство B будет продолжено.

First thing is we can not access a constructor of any class without an Object
then how it is initialize the constructor of abstract class if we can not create
an object of abstract class .

Вы произносите вышесказанное так, как будто вы рассматриваете А и В по-разному. Объект класса B также является объектом класса A. Это действительный объект в целом. Весь объект принадлежит классу B, но он содержит (как часть того же объекта) всю информацию, которая была из класса A.

...