Russian Qt Forum
Ноябрь 23, 2024, 08:07 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: Вызов private virtual метода  (Прочитано 13804 раз)
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #15 : Март 29, 2014, 15:37 »

нет, public/private - это реализация одного из фундаментальных принципов, инкапсуляции. Но из-за того, что С++ решил быть расширенным Си, всё оказалось довольно криво и обходимо
Не думаю, что в этом дело. Java вроде бы изначально планировалась как высокоуровневый ОЯП, что не спасает её от своего Public'а Морозова.

Ну и вообще что тут может сделать компилятор, кроме как вызвать A::Print? Запретить ослабление доступа для виртуальных функций на этапе компиляции? Бросить исключение/упасть на этапе исполнения?

Igors, а как вы оцениваете плохость/безыдейность Qt:
Код
C++ (Qt)
class A : public QObject
{
   Q_OBJECT
public:
   void emitSignal()
   {
       emit sA();
   }
signals:
   void sA();
};
 
class B : public QObject
{
   Q_OBJECT
 
private slots:
   void sB()
   {
       qDebug( "B" );
   }
};
 
int main(int argc, char *argv[])
{
   A a;
   B b;
   QObject::connect( &a, SIGNAL( sA() ), &b, SLOT( sB() ) );
   a.emitSignal();
}
 
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #16 : Март 29, 2014, 18:21 »

Где же "хак"?
Хак в том, что вы пытаетесь вызвать метод, который вызывать вам запрещено.

Аналогии с "#define private public" неуместны, то всего лишь кромсание исходников (благо макруха это позволяет)
В чем кромсание? Добавили одну строку перед инклюдом и получили, тот же эффект, что и у вас, да еще и без создания дополнительных/не нужных классов.
« Последнее редактирование: Март 29, 2014, 18:47 от Old » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #17 : Март 30, 2014, 09:30 »

Ну и вообще что тут может сделать компилятор, кроме как вызвать A::Print? Запретить ослабление доступа для виртуальных функций на этапе компиляции? Бросить исключение/упасть на этапе исполнения?
"За ЧТО?"  Улыбающийся

Igors, а как вы оцениваете плохость/безыдейность Qt:
Насколько я понял, приватный слот успешно коннектится. Не считаю это плохим/безыдейным, т.к. слоты могут активно использоваться для любых манипуляций, и не только ядром, но и приложением (напр PythonQt)
Записан
Bepec
Гость
« Ответ #18 : Март 30, 2014, 09:57 »

Хыхыхы... Похоже тут отсутствие информации сыграло свою роль. Igors - коннектятся слота самим объектом, которому принадлежит слот. А не "левым дядей".
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #19 : Март 30, 2014, 10:08 »

Хыхыхы... Похоже тут отсутствие информации сыграло свою роль. Igors - коннектятся слота самим объектом, которому принадлежит слот. А не "левым дядей".
Непонимающий Не понял, макрос SLOT вообще разворачивает в строку, какой дядя?
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #20 : Март 30, 2014, 10:52 »

Не понял, макрос SLOT вообще разворачивает в строку, какой дядя?
Ну это же вопрос реализации во что он разворачивается.
Я в данном коде для себя вижу нарушение «приватности» - мы адресуем приватный слот вне класса:
Цитировать
QObject::connect( &a, SIGNAL( sA() ), &b, SLOT( sB() ) );
то во что оно там под капотом Qt разворачивается дело 10-ое.
Логически аналогичный код с новой (Qt5) нотацией, например, вообще не соберётся:
Цитировать
QObject::connect( &a, &A::sA, &b, &B::sB );

Но тут вопрос скорее в идеологии Qt. Зачем слот вообще можно делать приватным?
Если просто что бы его нельзя было вызвать как функцию, то всё OK, а если что бы слот был доступен только внутри класса (а у меня такие потребности возникали), то это не работает в старой нотации.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #21 : Март 30, 2014, 10:59 »

Я в данном коде для себя вижу нарушение «приватности» - мы адресуем приватный слот вне класса:
Цитировать
QObject::connect( &a, SIGNAL( sA() ), &b, SLOT( sB() ) );
Ну чего же "адресуем", когда "вызываем" - хотя ни то ни другое неверно, это просто строка
"1sB()", синтаксис валидный
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #22 : Март 30, 2014, 13:18 »

Ну чего же "адресуем", когда "вызываем" - хотя ни то ни другое неверно, это просто строка
"1sB()", синтаксис валидный
А причем здесь, строка это или число? Это детали реализации.
Смысл здесь в том, что можем вызвать метод, который нам вызывать запрещено. Короче, это брат вашего хака. Улыбающийся
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #23 : Март 31, 2014, 01:41 »

Добрый день

Право, растерялся - если "private" то "извне" никак не вызвать. Однако простой пример ниже вызывает (печатается "А")
Код
C++ (Qt)
#include <stdio.h>
 
class A {
private:
virtual void Print( void ) { printf("A\n"); }
};
 
class B : public A {
public:
B( A & a ) : mA(a) {}
 
void Print( void ) { printf("B\n"); }
 
void Test( void )
{
B & b = static_cast <B &> (mA);
b.Print();
}
 
// data
A & mA;
};
 
int main(int argc, char *argv[])
{
A a;
B b(a);
b.Test();
 
return 0;
}
 
Please "ткните носиком" в статейки где это обсуждается


Запуск функции-члена происходит от имени класса B, в котором она определяется, как public.

Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #24 : Март 31, 2014, 01:57 »

Короче - квалификатор наследования может урезать права доступа (к базовому классу) но никогда их не расширит.

Компилятору пофигу, чего и как там было в базе.
Когда он делает проверку модификатора доступа, то он проверяет исключительно доступность конкретного метода от имени конкретного класса.

Если наследнику доступна функция-член предка, он вообще может по собственному желанию изменить его модификатор в своём пространстве имени:

http://rextester.com/XJOSPM85703

Код:
#include <iostream>
using namespace std;

struct A
{
protected:
   void foo() { cout<<"A::foo\n"; }
};

struct B: A   //<--- наследник имеет доступ к защищенному методу
{
public:
   using A::foo;  //<--- класс B захотел, что бы метод стал стал public
};

int main()
{
    std::cout << "Hello, world!\n";
   
    B b;
    b.foo();
}

И если в классе B объявлен метод Print с модификатором доступа public, значит его можно запустить снаружи.

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

Метод Print объявленный в классе B - собственность класса B, и поэтому модификатор этого метода определяется классом B.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #25 : Март 31, 2014, 09:18 »

struct B: A   //<--- наследник имеет доступ к защищенному методу
{
public:
   using A::foo;  //<--- класс B захотел, что бы метод стал стал public
};
К защищенному имеет, но не к приватному - using не пройдет если A::foo объявлено private. И часто затруднительно "иметь экземпляр B" только чтобы достучаться до A::foo
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #26 : Март 31, 2014, 09:19 »

И часто затруднительно "иметь экземпляр B" только чтобы достучаться до A::foo
define же. Улыбающийся
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #27 : Март 31, 2014, 23:14 »

К защищенному имеет, но не к приватному - using не пройдет если A::foo объявлено private. И часто затруднительно "иметь экземпляр B" только чтобы достучаться до A::foo

Верно.

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

http://rextester.com/ROT67619

Код:
#include <iostream>
using namespace std;

struct base
{
    virtual void foo()const { cout << __FUNCTION__ <<endl; }
};

struct der:base
{
    virtual void foo()const { cout << __FUNCTION__ <<endl; }
};


int main()
{
    std::cout << "Hello, world!\n";
    
    der d;
    
    d.foo();
    d.base::foo(); //<--- так как, она не приватна в имени класса base, то мы можем вытащить её из под тени
}

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

Каждый класс отвечает только за свою собственность и не отвечает ни за каких своих наследников.
Поэтому, в пространстве имени наследника можно установить любые модификаторы для собственности этого наследника, а так же для любого члена, к которому этот наследник имеет доступ.
Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.148 секунд. Запросов: 23.