2014-11-18 6 views
3

Взгляните на код. У меня есть интерфейс, который выглядит следующим образом:Доступ к частным функциям-членам производного класса с использованием ссылки на базовый класс

class Abstract_base { 
    public: 
     virtual ~Abstract_base() {} 

     virtual void f1() = 0; 
     virtual void f2() = 0; 
}; 

Базовый класс выглядит следующим образом:

class Base : public Abstract_base { 
    public: 
     virtual ~Base() {} 

     virtual void f1() override { cout << "f1" << endl; } 
     virtual void f2() override { cout << "f2" << endl; } 
}; 

и у меня есть два производного класса, как это:

class Derived_1 : public Base { 
    public: 
     virtual ~Derived_1() {} 

    private: 
     virtual void f2() override { cout << "Derived_1::f2()" << endl; } 

}; 

class Derived_2 : public Base { 
    public: 
     virtual ~Derived_2() {} 

    private: 
     virtual void f1() override { cout << "Derived_2::f1()" << endl; } 
}; 

и, наконец, у меня есть Handler класс, который выглядит следующим образом:

class Handler { 
    public: 
     Handler (Abstract_base& b) : base (b) {} 
     virtual ~Handler() {} 

     void process_1() { 
      base.f1(); 
     } 

     void process_2() { 
      base.f2(); 
     } 

    private: 
     Abstract_base& base; 
}; 

И main.cpp выглядит следующим образом:

int main (int argc, char** argv) { 

    Derived_1 der1; 
    der1.f2(); 

    Derived_2 der2; 
    der2.f1(); 

    Handler handler1 (der1); 
    handler1.process_2(); 

    Handler handler2 (der2); 
    handler2.process_1(); 

    return 0; 
} 

Конечно код не будет компилироваться, так как der1.f2() и der2.f1() являются частными, но если я закомментируйте эти две команды и оставить Handler1. process_2() и handler2.process_1() инструкции, код будет компилироваться и производить выход:

Derived_1::f2() 
Derived_2::f1() 

Вопрос:

Как я могу предотвратить вызов этих двух частных функций-членов, используя ссылку на Тез Класс act_base? Я просто не хочу, чтобы у пользователя был доступ к f2() в Derived_1 и f1() в Derived_2.

Насколько я знаю, я не мог использовать ключевое слово delete для Derived_1 :: f2() и Derived_2 :: f1().

Не могли бы вы предложить мне решение этой проблемы?

Решение

Я знаю, что один из раствора можно сделать обработчик класса шаблон:

template <class B> 
class Handler_templ { 
    public: 
     Handler_templ (B& b) : base (b) { } 
     virtual ~Handler_templ() {} 

     void process_1() { 
      base.f1(); 
     } 

     void process_2() { 
      base.f2(); 
     } 

    private: 
     B& base; 
}; 

и использовать его как это:

Handler_templ<Derived_1> h1 (der1); 
Handler_templ<Derived_2> h2 (der2); 

h1.process_2(); 
h2.process_1(); 

Что удивительно мне почему использование класса Handler я могу вызвать эти частные функции-члены? Для любых предложений я был бы очень благодарен.

С уважением, Артур

+2

Используя класс 'Handler', вы получаете доступ к методам с помощью ссылки на' Abstract_base', эта ссылка используется для определения доступа к функциям (здесь используется 'public'), поэтому компиляция кода. – Niall

ответ

1

_ "Как я могу предотвратить вызов этих двух частных функций-членов, используя ссылку на класс Abstract_base? Я просто не хочу, чтобы пользователь имел доступ к f2() в Derived_1 и f1() в «Derived_2» ._

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

«Что меня удивило в том, почему использование класса Handler я могу вызвать эту частную функцию-член?"

Как для образцов

class Base : public Abstract_base { 
public: 
    virtual ~Base() {} 
    virtual void f1() override { cout << "f1" << endl; } 
    virtual void f2() override { cout << "f2" << endl; } 
}; 

class Derived_1 : public Base { 
public: 
    virtual ~Derived_1() {} 
private: 
    virtual void f2() override { cout << "Derived_1::f2()" << endl; } 
}; 

class Derived_2 : public Base { 
public: 
    virtual ~Derived_2() {} 
private: 
    virtual void f1() override { cout << "Derived_2::f1()" << endl; } 
}; 

это совершенно нормально, чтобы переопределить функцию public базового класса, используя private функцию в производном классе.
Эти функции переопределения будут по-прежнему видны через интерфейсы классов Base/Abstract_base.

Спецификатор области private делает их недоступными для непосредственного вызова клиентов.

1

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

Согласно Лиск принципу замещения (LSP),

Функции, которые используют указатели или ссылки на базовые классы должны быть в состоянии использовать объекты производных классов, не зная его ,

+0

_ «Вы не можете этого сделать». _ Вы не можете делать то, что на самом деле? Запретить клиентам, вызывающим виртуальные функции, которые реализуются в классе «private» классов? –

+1

Я исправил это, согласно вопросу OP. – songyuanyao

0

Вы не можете этого сделать. Вы не можете предотвратить две вещи:

Derived_1 der1; 
((Abstract_base*)&der1)->f2(); // 1 

и указатель или ссылочное преобразование:

Derived_1 d; 

Abstract_base* bp = &d; // 2 
Abstract_base& ref = d; // 2 

C++ не имеет положения, чтобы остановить преобразование в базовый указателе/​​ссылку, или для выполнения объектно-нарезки на базу. Ни C++ не указывает, что производный класс должен реализовывать виртуальную функцию на определенном уровне защиты.