Чому я повинен використовувати ключове слово “using” для доступу до методу свого базового класу?


75

Я написав наведений нижче код, щоб пояснити свою проблему. Якщо я коментую рядок 11 (з ключовим словом «використовуючи»), компілятор компілює цей файл і виводить повідомлення про помилку: invalid conversion from 'char' to 'const char*'. Це , здається, не бачить метод void action(char)в Parentкласі в Sonкласі.

Чому компілятор поводиться так? Або я зробив щось не так?

class Parent
{
    public:
        virtual void action( const char how ){ this->action( &how ); }
        virtual void action( const char * how ) = 0;
};

class Son : public Parent
{
    public:
        using Parent::action; // Why should i write this line?
        void action( const char * how ){ printf( "Action: %c\n", *how ); }
};

int main( int argc, char** argv )
{
    Son s = Son();
    s.action( 'a' );
    return 0;
}

Скажіть, будь ласка: що, якщо ви видалите const у "const char how"?
Павло Радзивіловський

31
Набирати текст не потрібно Son s = Son();. Це просто створює тимчасове, а потім викликає конструктор копіювання. Просто введітьSon s;
Чарльз Сальвія


Відповіді:


63

actionОголошено в похідному класі приховує , actionоголошені в базовому класі. Якщо ви використовуєте actionна Sonоб'єкті, компілятор буде шукати методи, декларовані у Son, знайти один із них action, що використовується, і використовувати це. Він не буде продовжувати пошук у методах базового класу, оскільки він уже знайшов відповідне ім'я.

Тоді цей метод не відповідає параметрам виклику, і ви отримуєте помилку.

Див. Також поширені запитання щодо C ++, щоб отримати додаткові пояснення щодо цієї теми.


9
@sth Добре це знати. але це, можна сказати, особливість c ++ чи якась помилка? чи не псує це всю ідею спадкування? просто питаю ..
Сумуду

Чи відбувається збіг імен із використанням спотвореного імені, чи відіграє тут роль перевантаження методу, чи перша викликана функція, що має назву "дія", і все?
tmaric

4
@Anubis: Правило спрощує пошук імен. Без цього компілятору потрібно було б пройти повне дерево успадкування, коли йому потрібно вирішити ім'я функції-члена (у якомусь базовому класі може бути перевантаження функції). За допомогою правила компілятор може перестати дивитись на решту дерева успадкування, як тільки він знайшов клас, що містить відповідне ім'я. У такій же ситуації і програміст. Переглядаючи похідний клас, він може бути впевнений, що визначена там функція буде викликана, не знаючи, чи може якийсь базовий клас містити іншу функцію з тим самим іменем.
sth

18

Дивно, що це стандартна поведінка. Якщо похідний клас оголошує метод з тим самим іменем, що і метод, визначений базовим класом, метод похідного класу приховує базовий клас.

Див. Поширені запитання про C ++


6

Примітка обережності: необхідність використання "використання" в цій ситуації є червоним позначкою того, що ваш код може заплутати інших розробників (адже це збило компілятор з ладу!). Ймовірно, вам слід перейменувати один із двох методів, щоб зробити різницю зрозумілою для інших програмістів.

Одна можливість:

void action( const char how )
{ 
  takeAction( &how ); 
}
void action( const char * how )
{
  takeAction(how);
}
virtual void takeAction(const char * how) = 0;

6

Якщо в похідному класі будь-яка перевантажена функція перевизначена, тоді вся перевантажена функція в базовому класі прихована. Один із способів включити обидві функції - це уникнути перевантаження функцій у класах. або Ви можете використовувати usingключове слово, як використовується.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.