среда, 7 июля 2010 г.

Final class в С++

Последнее время приходится проводить много собеседований. С одной стороны занимает много времени и сил, а с другой дополнительный стимул расти самому.
Вот недавно всплыл такой вопрос: можно ли запретить наследование от класса в С++. В Java есть такое понятие как final класс, т.е. класс от которого нельзя наследоваться.

Предположим есть некий класс А:

class A
{
public:
A(){}
~A(){}
};

и класс B

class B : public A //все отлично собирается
{
};


Необходимо сделать так, чтобы при попытке наследование компилятор выдавал сообщение об ошибке.

Первое, что приходит в голову это сделать конструктор и деструктор класса А приватными. Действительно после этого я не смогу наследоваться, но возникает другая проблема - я не могу создавать экземпляры класса А.
Пытаемся развить мысль далее. Что если переопределить для класса А операторы new и delete. Так как это будут операторы класса, то они смогут получить доступ к приватным конструктору и деструктору. Получается вот такой класс:

class A
{
private:
A(){}
~A(){}


public:
void* operator new(size_t size)
{
return ::operator new(size);
}

void operator delete(void* block)
{
::operator delete(block);
}
};

сlass B : public A //компилятор ругается
{
};


Но на самом деле это не работает. Переопределенные операторы new\delete все равно не получают доступа к приватным конструктору и деструктору класса А. Объявление операторов new\delete друзьями класса А тоже не помогает.

Второй мыслью (после часа попыток) было полезть во всемирную паутину и найти ответ там. Ответ я нашел, но не на все вопросы. Итак реализация final класса для С++ выглядит следующим образом:

class ClassLocker
{
friend class A;
private:
ClassLocker(){}
};

class A : public virtual ClassLocker
{
public:
A(){}
~A(){}
};

class B : public A //компилятор выдает сообщение об ошибке
{
};

Самое интересное, что если мы убрать виртуальное наследование класса А от класса ClassLocker, т.е. написать class A : public ClassLocker, то все отлично собирается. Слово virtual в данном случае является ключевым.

Итак в итоге есть два вопроса:
  • Почему переопределенные операторы new\delete не имеют доступа к приватном конструктору и деструктору?
  • Почему именно виртуальное наследование запрещает дальнейшее наследование?
Ответы на вопросы я дам в следующей статье.

Всем доброй ночи.

пятница, 11 июня 2010 г.

Блог Джона Роббинса

Читаю книгу Роббинса об отладке приложений. Одна из тех книг, которые стоит прочитать всем. Программистам конечно.

Всем доброй ночи