Доступ к частной функции с использованием виртуальной функции - PullRequest
0 голосов
/ 26 января 2019

Как избежать Закрытая функция, вызываемая косвенно с использованием виртуальной функции базового класса.

class baseclass{
public:
    virtual void printmynumber() = 0;
};

class derivedclass : public baseclass
{
private:
    int m_mynumber;
    void printmynumber()
    {
        cout << m_mynumber << endl; 
    }
public:
    derivedclass(int n)
    {
       m_mynumber = n;
    }
};


void main()
{
    baseclass *bObj = new derivedclass(10);
    bObj->printmynumber();
    delete bObj;
}

Как избежать вызова приватной функции?

Ответы [ 3 ]

0 голосов
/ 26 января 2019

Вы не можете сделать это с наследованием. Имея указатель на baseclass, компилятор знает только, что он имеет функцию public virtual, поэтому позволяет вызывать функцию соответствующим образом.

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

Ничто не мешает реализации derivedclass::printmynumber() ничего не делать - это означает, что если код вызывает его, заметного эффекта не будет (при условии, что отсутствие ожидаемого эффекта допустимо).

Настоящее решение состоит в том, чтобы исправить ваш дизайн, а не пытаться обойти его недостатки. Не наследуйте derivedclass от baseclass. Таким образом, никакая функция-член derivedclass не может быть вызвана вообще, учитывая только указатель на baseclass, так как типы не связаны (передача derivedclass * функции, ожидающей baseclass *, обычно диагностируется как ошибка).

Кстати: main() возвращает int, а не void. Некоторые компиляторы поддерживают void main() как нестандартное расширение (а документация для некоторых из этих компиляторов ошибочно описывает такую ​​вещь как стандарт), но этого лучше избегать.

0 голосов
/ 26 января 2019

Единственный способ предотвратить это без изменения базового класса - добавить еще один уровень наследования между исходным базовым классом и конечным производным классом. В этом среднем классе вы делаете функцию частной или удаленной. И затем вы используете указатель на этот средний класс в качестве базового указателя.

Что-то вроде

class baseclass
{
public:
    virtual void printmynumber() = 0;
};

struct middleclass : public baseclass
{
    void printmynumber() = delete;
};

class derivedclass : public middleclass
{
private:
    int m_mynumber;
    void printmynumber()
    {
        cout << m_mynumber << endl; 
    }
public:
    derivedclass(int n)
    {
       m_mynumber = n;
    }
};


void main()
{
    // Here use the middleclass instead of the baseclass
    middleclass *bObj = new derivedclass(10);

    // printmynumber is deleted in the middleclass and can't be called
    // This will result in a build error
    bObj->printmynumber();

    delete bObj;
}

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

0 голосов
/ 26 января 2019

Вы не можете.

void printmynumber() является частью общедоступного API baseclass, следовательно, derivedclass. Если вы хотите, чтобы derivedclass::printmynumber() не был публичным, возможно, derivedclass не должен наследовать от baseclass.

Как указано в комментариях, это является нарушением принципа замены Лискова : L в SOLID .

...