2016-07-11 5 views
1

Предположим, у меня есть два класса: A и B и B - A.Функциональная подпись и наследование в C++

Класс A:

class A 
{ 
public: 
    virtual const unsigned char* getArray() 
    { 
     return array; 
    } 

protected: 
    unsigned char array[250]; 
}; 

Класс B:

class B : public A 
{ 
public: 
    virtual unsigned char* getArray() 
    { 
     return array; 
    } 
}; 

Могу ли я создать класс C, который будет делать это?

class C 
{ 
public: 
    const unsigned char* getArrayMiddle(A &a) 
    { 
     return (a.getArray() + 125); 
    } 

    unsigned char* getArrayMiddle(B &b) 
    { 
     return (b.getArray() + 125); 
    } 
}; 

С помощью этого простого примера, я пытаюсь узнать, если я могу создать два метода в классе C, один из них возвращается константный указатель, если требуется по типу объекта он получает.

Будет ли компилятор автоматически вызывать правильный метод в C в зависимости от типа параметра, даже если B получает A?

Чтобы уточнить, если у меня есть

A* obj = new B(); 
C c; 
c.getArrayMiddle(*obj); 

, какая функция будет называться? Может ли это создать непредвиденные ситуации?

+0

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

+0

Я действительно проверил и скомпилировал его. Я также задаю вопрос, чтобы убедиться, что такого рода вещи не требуют дополнительной меры предосторожности для использования или не могут заставить меня в беде в некоторых ситуациях. – rgaillard

+0

У них разные подписи, поэтому это не проблема. Тем не менее, я бы не рекомендовал иметь одинаковые имена публичных методов при выводе класса без переопределения. –

ответ

2

Будет ли компилятор автоматически вызывать соответствующий метод C в зависимости от типа параметра, даже если B происходит A?

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

Если статический тип аргумента равен B &, тогда будет вызываться второй вариант (возврат unsigned char *). Если это не B &, а A &, тогда будет вызываться первый вариант (возврат const unsigned char *).

Точные правила, определяющие, какой перегруженный метод вызывается, в которых обстоятельства являются довольно сложными, но обычно предпочтительным является подходящий кандидат . В этом случае B & более конкретно, чем A &, поэтому он будет вызываться, если аргумент равен B &, хотя он в этом случае тривиально конвертируется в A & из-за иерархии наследования.

Однако, стоит отметить, что (согласно комментарию от cpplearner) ваш код, как опубликовано, не должен компилироваться. B не может переопределить getArray с версией, которая отбрасывает квалификатор const. G ++ 5.4 диагностирует это как ошибку. Вместо этого вы можете не использовать один метод для другого: отпустите спецификатор virtual или укажите им разные имена или отметьте метод в A как метод const.

+0

Хорошо спасибо, это именно то, что я хотел знать и чего я ожидаю. – rgaillard

+0

Я не согласен. Хотя технически это правильно, это игнорирует возможность неожиданных результатов, когда где-то внутри C он вызывает виртуальную функцию. Но только в том случае, если в vtable есть выбор, чего нет в исходном вопросе, поэтому ... Наверное, вы ответили на исходный вопрос, как было задано. –

+0

@KennyOstrom не уверен, что вы имеете в виду. Он * * вызывает виртуальный метод изнутри 'C' - это' getArray'. Если вы вызываете виртуальный метод, вы должны ожидать, что он может быть переопределен и что будет вызываться наиболее производный вариант. Если вы ожидали чего-то другого, это должно было быть связано с неправильным пониманием правил языка. – davmac