Как обнаружить и отстоять виртуальное наследование для определенного класса - PullRequest
9 голосов
/ 19 декабря 2011

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

Я быкак какой-то способ утверждать это требование либо во время компиляции, либо, по крайней мере, во время выполнения.

Есть ли способ достичь этого?

Ответы [ 3 ]

9 голосов
/ 19 декабря 2011

Что-то вроде этого?

struct RefCounter {
    template <typename T>
    RefCounter(T *) {
        BOOST_STATIC_ASSERT(boost::is_virtual_base_of<RefCounter, T>);
    }
};

struct GoodClass : virtual RefCounter {
    GoodClass() : RefCounter(this) {}
};

struct BadClass : RefCounter {
    BadClass() : RefCounter(this) {}
};

Обидно, что нужно передать this в конструктор, чтобы захватить производный тип.И, конечно, умышленно тупой пользователь может подорвать его, передав что-то отличное от this.

5 голосов
/ 19 декабря 2011

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

struct RefCounterVirtPrivate_
{
    int count;

    RefCounterVirt()
        : count( 0 )
    { }
};

struct RefCounter : public virtual RefCounterVirtPrivate_
{
};

struct A : public RefCounter { };
struct B : public RefCounter { };
struct C : public A, public B { };

Тогда все может наследоваться от RefCounter без необходимости заботиться о виртуальном наследовании.Вам даже не нужно изменять какой-либо существующий код - виртуальное наследование самого RefCounter должно быть безвредным.

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

0 голосов
/ 19 декабря 2011

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

В зависимости от вашего приложения выможет потребоваться оставить точное время, когда он вызывает delete this; для реализации объекта, то есть иметь только абстрактные функции add_ref() и release() в базовом классе (что позволяет одной конкретной реализации отображаться во всех интерфейсных таблицах справильное оповещение) и возложите бремя поддержания счетчика ссылок на конкретный класс.

...