Есть ли способ запретить вызов метода базового класса в производном классе? - PullRequest
0 голосов
/ 20 сентября 2019

В c ++ модификатор «protected» разрешает вызовы методов только в производных классах.Можно ли реализовать обратную логику - запретить вызов метода базового класса в производных классах?Код ниже иллюстрирует то, что я хочу получить.

class Base
{
   int data;
protected:
   // This constructor should be called only in the derived classes
   Base(int d): data(d) { }
public:
   // This construcor can be called wherever except a derived classes!
   Base(): data(0) { }
};

class Derived : public Base
{
public:
   // The developer must not forget to initialize "data"
   Derived() : Base(10) {}

   // I want to get a compilation error there
   Derived() : Base() {}
};

Ответы [ 4 ]

2 голосов
/ 20 сентября 2019
// This construcor can be called wherever except a derived classes!

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

2 голосов
/ 20 сентября 2019

Можно ли [...] запретить вызов метода базового класса в производных классах?

Да.Используя частный спецификатор доступа.Частные имена доступны только самому классу.

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

1 голос
/ 20 сентября 2019

Это похоже на проблему XY.Хотя я не рекомендую это (я рекомендую переосмыслить дизайн), я нашел (к лучшему или худшему) решение, основанное на шаблоне CRTP:

template <class D = void>
class Base
{    
protected:

    int data;

protected:
    // This constructor should be called only in the derived classes
    template <class Der = D, class = std::enable_if_t<std::is_base_of_v<Base, Der>>>
    Base(int d): data(d) {}

public:
    // This constructor can be called wherever except a derived classes!
    template <class Der = D, class = std::enable_if_t<!std::is_base_of_v<Base, Der>>>
    Base(): data(0) { }
};

class Derived : public Base<Derived>
{
    int mydata = 1;
public:
    // The developer must not forget to initialize "data"
    Derived() : Base(24) {}

    // I want to get a compilation error there
    //Derived() : Base() {} // (1) compilation error here
};
auto test()
{
    Base b1{};
    //Base b2{24}; // (2) compilation error here

    Derived d{};
}

Конечно, есть проблемы с этим.Начнем с того, что ничто не мешает создать производный класс как class Derived : public Base<void>.

. Если хотите, вы можете добавить общий базовый класс

class Base_l0
{
};

template <class D = void>
class Base_l1 : Base_l0
{
};

class Derived : public Base_l1<Derived>
{
};
.
0 голосов
/ 20 сентября 2019

Краткий ответ - нет.

В C ++ есть только public protected и private.Там нет никакого среднего.Ваши функции доступны либо везде (public), ниоткуда, кроме самого класса (private), либо из класса и его дочерних элементов (protected).

Я только хочу заставить пользователя выполнить некоторые дополнительные действия, наследуя [sic].Например, чтобы избежать случайных ошибок.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...