Наследование C++ и указатели функции членства

В этих случаях вы должны придерживаться getElementById(), например:

document.getElementById('example').innerHTML

IE любит смешивать элементы с атрибутами name и ID в глобальное пространство имен, поэтому лучше всего указать, что вы пытаетесь получить.

46
задан smh 15 July 2009 в 10:52
поделиться

7 ответов

C ++ 03 std, §4.11 2 Преобразования указателя на член :

Rvalue типа «указатель на член B типа cv T», где B - тип класса, может быть преобразован в rvalue типа «указатель на член D типа cv T», где D - производный класс (пункт 10) от B. Если B - недоступный (пункт 11 ), неоднозначный (10.2) или виртуальный (10.1) базовый класс D, программа, которая требует этого преобразования, плохо сформирована. Результат преобразования относится к тому же члену, что и указатель на член до того, как произошло преобразование, но он относится к члену базового класса, как если бы он был членом производного класса. Результат относится к члену в экземпляре D из B. Поскольку результат имеет тип «указатель на член D типа cv T», его можно разыменовать с помощью объекта D. Результат такой же, как если бы указатель на член B был разыменован с подобъектом B объекта D.Значение указателя нулевого члена преобразуется в значение указателя нулевого члена целевого типа. 52)

52) Правило преобразования указателей на члены (от указателя на член базы в указатель на член производного) кажется инвертированным по сравнению с правилом для указателей на объекты (от указателя к производному). на указатель на базу) (4.10, п.10). Эта инверсия необходима для обеспечения безопасности типов. Обратите внимание, что указатель на член не является указателем на объект или указателем на функцию, и правила преобразования таких указателей не применяются к указателям на члены. В частности, указатель на член не может быть преобразован в void *.

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

class A {
public: 
    void foo();
};
class B : public A {};
class C {
public:
    void bar();
};
class D {
public:
    void baz();
};
class E : public A, public B, private C, public virtual D {
public: 
    typedef void (E::*member)();
};
class F:public E {
public:
    void bam();
};
...
int main() {
   E::member mbr;
   mbr = &A::foo; // invalid: ambiguous; E's A or B's A?
   mbr = &C::bar; // invalid: C is private 
   mbr = &D::baz; // invalid: D is virtual
   mbr = &F::bam; // invalid: conversion isn't defined by the standard
   ...

Преобразование в другом направлении (через static_cast ) регулируется § 5.2.9 9:

rvalue типа «указатель на член D типа ] cv1 T "может быть преобразовано в rvalue типа" указатель на член B типа cv2 T ", где B - базовый класс (пункт 10 class.dehibited ]) D, если существует допустимое стандартное преобразование из «указателя на член B типа T» в «указатель на член D типа T» ( 4.11 conv.mem ) и cv2 - это то же cv-квалификация, что и, или большее cv-квалификация, чем, cv1 . 11) Значение указателя нулевого члена ( 4.11 усл.mem ) преобразуется в значение указателя нулевого члена целевого типа. Если класс B содержит исходный член или является базовым или производным классом класса, содержащего исходный член, результирующий указатель на член указывает на исходный член.В противном случае результат приведения не определен. [Примечание: хотя класс B не обязательно должен содержать исходный член, динамический тип объекта, на котором разыменовывается указатель на член, должен содержать исходный член; см. 5.5 expr.mptr.oper .]

11) Типы функций (включая те, которые используются в типах указателя на функцию-член ) никогда не квалифицируются cv; см. 8.3.5 dcl.fct .

Короче говоря, вы можете преобразовать производный D :: * в базовый B :: * , если вы можете преобразовать из B :: * в D :: * , хотя вы можете использовать B :: * только для объектов типа D или потомков D.

{{1} }
28
ответ дан 26 November 2019 в 20:39
поделиться

Вы могли бы хотеть проверить эту Функцию членства статьи Указатели и Самые Быстрые Делегаты C++ , короткий ответ, кажется, в некоторых случаях.

3
ответ дан dagorym 26 November 2019 в 20:39
поделиться

Я не на 100% уверен, что Вы спрашиваете, но вот пример, который работает с виртуальными функциями:

#include <iostream>
using namespace std;

class A { 
public:
    virtual void foo() { cout << "A::foo\n"; }
};
class B : public A {
public:
    virtual void foo() { cout << "B::foo\n"; }
};

int main()
{
    void (A::*bar)() = &A::foo;
    (A().*bar)();
    (B().*bar)();
    return 0;
}
11
ответ дан Matt Price 26 November 2019 в 20:39
поделиться

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

1
ответ дан Steve Duitsman 26 November 2019 в 20:39
поделиться

My experimentation revealed the following: Warning - this might be undefined behaviour. It would be helpful if someone could provide a definitive reference.

  1. This worked, but required a cast when assigning the derived member function to p.
  2. This also worked, but required extra casts when dereferencing p.

If we're feeling really ambitious we could ask if p can be used to point to member functions of unrelated classes. I didn't try it, but the FastDelegate page linked in dagorym's answer suggests it's possible.

In conclusion, I'll try to avoid using member function pointers in this way. Passages like the following don't inspire confidence:

Casting between member function указатели - чрезвычайно темная область. Во время стандартизации C ++ было много дискуссий о сможете ли вы бросить указатель на функцию-член из одного класса на указатель функции-члена базы или производный класс, и независимо от того, может переходить между несвязанными классами. К тому времени комитет по стандартам решили, другой компилятор поставщики уже сделали решения по реализации, которые запер их в разные ответы на these questions. [FastDelegate article]

1
ответ дан 26 November 2019 в 20:39
поделиться

Предположим, что у нас есть класс X, класс Y: публичный X и класс Z: публичный Y

У вас должна быть возможность назначать методы для обоих X, Y указателям типа void (Y :: * p) (), но не методы для Z. Чтобы понять, почему, рассмотрите следующее:

void (Y::*p)() = &Z::func; // we pretend this is legal
Y * y = new Y; // clearly legal
(y->*p)(); // okay, follows the rules, but what would this mean?

Разрешив это назначение, мы разрешаем вызов метода Z для объекта Y, который может привести неизвестно к чему. Вы можете заставить все это работать, применяя указатели, но это небезопасно или гарантированно сработает.

1
ответ дан 26 November 2019 в 20:39
поделиться

Критическая проблема с указателями на члены заключается в том, что они могут применяться к любой ссылке или указателю на класс правильного типа. Это означает, что поскольку Z является производным от Y , указатель (или ссылка) указателя типа (или ссылки) на Y может фактически указывать (или ссылаться) на подобъект базового класса Z или любого другого класса , производный от Y .

void (Y::*p)() = &Z::z_fn; // illegal

Это означает, что все, что назначено указателю на член Y , должно фактически работать с любым Y . Если бы было разрешено указывать на член Z (который не был членом Y ), тогда можно было бы вызвать функцию-член Z о чем-то, что на самом деле не было Z .

С другой стороны, любой указатель на член Y также указывает на член Z (наследование означает, что Z имеет все атрибуты и методы его основание) допустимо преобразовать указатель на член Y в указатель на член Z . Это безопасно по своей сути.

void (Y::*p)() = &Y::y_fn;
void (Z::*q)() = p; // legal and safe
7
ответ дан 26 November 2019 в 20:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: