Звучит так, будто вы хотите сделать что-то вроде этого:
class Base
{
public:
virtual void foo(Base&) = 0;
};
class A : public Base
{
public:
void foo(A&);
};
class B : public Base
{
public:
void foo(B&);
};
В объектно-ориентированном проектировании это известно как ковариация (в частности, тип аргумента ковариантного метода)").
Проблема в том, что это противоречит принципам хорошего объектно-ориентированного проектирования.Принцип подстановки Лискова гласит, что если у вас есть базовый класс Base
, то любые экземпляры подклассов Base
должны быть взаимозаменяемыми - но вы хотите, чтобы некоторые подклассы Base
не работали сдругие подклассы Base
.(Это упрощение, но есть много дискуссий в Интернете с более подробной информацией.)
Если вы хотите сделать это - если это лучшее решение в вашем случае, несмотря на общие рекомендации замены Лисковапринцип - тогда вы можете выполнить проверки самостоятельно.
void A::foo(Base& base_arg) {
// This will throw a runtime exception if the wrong type
A& arg = dynamic_cast<A&>(base_arg);
std::cout << mClassA << std::endl;
}
Обратите внимание, что вы жертвуете некоторой безопасностью типа времени компиляции сейчас - если вы случайно попытаетесь вызвать A::foo
с экземпляром B
,вы не будете знать, пока код не будет запущен, и вы получите исключение.(В этом весь смысл виртуальных функций / динамической диспетчеризации / полиморфизма - поведение определяется во время выполнения.)
Другой подход заключается в использовании шаблонов, таких как @ решение Стивена Лехнера .Это избавляет от полиморфизма во время выполнения, но сохраняет строгую безопасность типов и лучше следует традиционному OO-дизайну.
Статья Википедии о ковариации содержит гораздо больше обсуждений, включая дополнительный пример кода.