Чому я повинен використовувати ключове слово “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.