Я использую класс для объявления интерфейса. Я просто хочу определить сигнатуру метода. Этот метод должен быть реализован в любом неабстрактном подклассе. Мне не нужен метод, чтобы быть виртуальным. Это поведение по умолчанию в C # BTW (я пришел из C # / мир Java)
Однако, кажется, в C ++ это невозможно. Я либо объявляю метод в обычном порядке
void Foo::Method()
и тогда не обязательно реализовывать его или объявлять метод как «чисто виртуальный»
void virtual Foo::Method() = 0;
и тогда метод становится виртуальным, но я хочу избежать этого, чтобы немного сохранить производительность.
Кажется, я хочу что-то подобное
void Foo::Method() = 0;
но это было бы ошибка компиляции
если вы планируете использовать производный класс из кода шаблона, то есть полиморфизм времени компиляции, то вам нужно только документировать ожидаемую подпись
код, использующий производный класс, просто не будет компилироваться и связываться, если используемая функция не реализована
в противном случае для полиморфизма во время выполнения он должен быть виртуальным, иначе он не будет вызван
Я полагаю, что вы можете быть смущены тем, как работает версия C #:
class A {
public void NonVirt() { Console.Out.WriteLine("A:NonVirt"); }
public virtual void Virt() { Console.Out.WriteLine("A:Virt"); }
}
class B : A {
public void NonVirt() { Console.Out.WriteLine("B:NonVirt"); }
public override void Virt() { Console.Out.WriteLine("B:Virt"); }
}
class Program {
static void Main(string[] args) {
A x = new B();
x.NonVirt();
x.Virt();
}
}
Это будет выводить
A:NonVirt
B:Virt
Так что даже в C # вам нужно сделать метод виртуальным, если вы хотите вызвать производную реализацию.
Если метод должен быть реализован во всех неабстрактных подклассах, это означает, что вам нужно вызывать их через указатель базового класса. Это, в свою очередь, означает, что вам нужно сделать их виртуальными, как в C # (и, вероятно, в Java, но я не уверен)
Кстати, цена виртуального звонка на современных процессорах составляет несколько наносекунд, поэтому я не уверен, стоит ли это того, но стоит сказать, что это так.
Если вы хотите избежать стоимости виртуального вызова, вы должны использовать полиморфизм времени компиляции через шаблоны
В C ++ нет понятия интерфейса. Единственный способ достичь своей цели — создать базовый класс, определяющий как virtual
а также = 0
все методы, которые должны быть фактически определены в подклассах.
class IBase {
// ...
virtual void f1() = 0;
// ....
}
Этот класс будет виртуально чистым, если все методы определены как f1
, который является ближайшим к интерфейсу, который вы можете получить.
Концепция интерфейса в Java немного похожа на контракт в отношении классов, реализующих его. Компилятор обеспечивает соблюдение ограничений контракта путем проверки содержимого разработчиков. Это понятие контракта или явный структурный подтип формально не существует в C ++.
Однако вы можете вручную проверить, соблюдаются ли такие ограничения, определив шаблон, который будет ожидать в качестве параметра класс с определенными методами или атрибутами, и используя этот шаблон в проверяемых классах. Полагаю, это можно считать формой модульного тестирования.