Почему C++ выбирает перегрузку базового класса при использовании указателя на функцию-член производного класса?

Я пытаюсь понять, как C++ обрабатывает указатели на функции-члены и разрешение перегрузки в контексте наследования. У меня есть базовый класс с чистой виртуальной функцией и производный класс. Я перегрузил функцию doSomething, чтобы принимать указатели на функции-члены как из базового, так и из производных классов. Вот код:

#include <iostream>

class Base {
    public:
        virtual void foo() = 0;
};

class Derived: public Base {};

void doSomething(void (Base::*func)(void)) {
    std::cout << "Base overload\n";
}

void doSomething(void (Derived::*func)(void)) {
    std::cout << "Derived overload\n";
}

int main(void) {
    doSomething(&Derived::foo);
}

Когда я запускаю этот код, результат:

Base overload

Я ожидал, что будет вызвана «Производная перегрузка», потому что я передаю адрес Derived::foo. Может ли кто-нибудь объяснить, почему в этом сценарии выбрана «Базовая перегрузка»? Мне интересно понять основные механизмы C++, которые приводят к такому поведению.

&Derived::Foo является/относится к &Base::Foo как непереопределенному.
Jarod42 29.08.2024 09:34

Если вы добавите метод override, он будет работать так, как вы ожидаете Демо

Jarod42 29.08.2024 09:38

Еще одна песочница, чтобы показать больше случаев Демо

Jarod42 29.08.2024 09:45

«почему в этом сценарии выбрана «Базовая перегрузка»?...» Потому что Тип выражения &Derived::foo равен void (Base::*)(), а не void (Derived::*)()

user12002570 29.08.2024 09:47
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
74
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Просто потому, что Derived не объявляет свой собственный foo, а наследует его от Base. Если вы переопределите (или затените) его, тип изменится на ... (Derived::*)(...).

Иногда это полезно в шаблонах, чтобы определить, была ли определенная функция переопределена или нет.

Стоимость

std::is_same_v<decltype(&Derived::foo), decltype(&Base::foo)>

это true, потому что ваш Dereived не предоставляет собственного переопределения void foo. Итак, void doSomething(void (Base::*foo)(void)) выбран. Оно изменится, если вы добавите void foo() override; к своему Derived.

Другие вопросы по теме

Почему «Размещение нового» для классов с виртуальными членами работает только тогда, когда буфер находится в локальном стеке?
Почему размер этого подкласса такой же, как у базового класса, хотя он добавляет переменную-член?
Разрешено ли передавать «это» производного класса конструктору базового класса?
Вызов виртуального метода C++ из Rust вызывает ошибку нарушения прав доступа даже после успешного выполнения
Почему в C++ нет функции расширения виртуальных функций?
Метод базового класса не вызывается для объекта производного типа: полиморфизм без указателя и ссылки
Есть ли в этом случае обходной путь для шаблона виртуальной функции с ограничением типа?
Почему вызов виртуального метода в конструкторе и привязка виртуального метода с последующим его вызовом дают разные результаты?
Вызов метода базового класса с помощью std::function
Вызов метода базового класса с помощью std::function

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

Почему возникает состояние гонки, когда аппаратное обеспечение обеспечивает согласованность
Производный виджет Gtk::DrawingArea загружается из файла компоновщика Glade неправильно
Ошибка нарушения прав доступа при многопоточном сканировании диска с помощью C++
Является ли замена всех const std::string & на std::string_view хорошим выбором?
C++ Неопределенное поведение при использовании переинтерпретации приведения
Как получить понятное имя, принадлежащее дескриптору HMONITOR в Windows?
Цикл while в C++ завершается сбоем, если целое число содержит более 10 цифр
Какова точная цитата из стандарта C++, в которой говорится, что ошибка вывода типа при выведении аргумента шаблона не является ошибкой (SFINAE)?
Метод удаления двоичного дерева поиска удаляет все узлы, а не только выбранный C++
Ошибка Boost::program_options «опция не может быть указана более одного раза» при реализации программы с несколькими режимами