Два действительно похожих класса в C ++ только с одним другим методом: как реализовать? - PullRequest
3 голосов
/ 04 сентября 2010

У меня есть два почти идентичных класса, кроме одного метода. Классы имеют одинаковую часть данных и все функции-члены, но одну:

class A {
private:
  double data;
public:
  double calc(){
     return data*data;
  }
   double especific(){
     return 2.0*data;
  }
 }

и второй класс идентичен, кроме специфического метода.

Эта функция-член, в частности, требует вычисления всех данных-членов, поэтому передача по значению или ссылке не является опцией. Есть ли способ реализовать это без большого дублирования кода? Использование только одного класса или использование шаблонов, но не наследование (огромное влияние на производительность).

Спасибо

РЕДАКТИРОВАТЬ : Спасибо за все ответы. Шаблон «Стратегия» может помочь в моем случае, я попробую и посмотрю, работает ли он. Я избегаю виртуального наследования как чумы, основанной на некоторых тестах, которые я проводил в другой программе. Эта процедура будет вызываться везде, и производительность является очень важным фактором.

Ответы [ 9 ]

9 голосов
/ 04 сентября 2010

Это похоже на работу для паттерна стратегии .Это может быть реализовано в этом случае в качестве параметра шаблона.Часто это будет реализовано как параметр конструктора или метод установки в классе, но для правильной работы потребуется наследование.

В этом случае что-то вроде:

template <class SpecificStrategy>
class A {
 private:
    double data;
 public:
    double calc(){
       return data*data;
    }
    double especific() {
       return SpecificStrategy::especific(data);
    }
};

class DoubleStrategy {
   static double especific(double data) {
      return 2 * data;
   }
};
class TripleStrategy {
   static double especific(double data) {
      return 3 * data;
   }
};

Тогда выможно сослаться на:

A<DoubleStrategy> x;
A<TripleStrategy> y;

x и y будут совершенно не связанных типов, но, похоже, в данном случае это не то, что вы хотите.Мнение с использованием виртуальной функции и наследования - путь.Как кто-то еще отметил, снижение производительности не так велико.Однако есть обстоятельства, при которых я вижу, что это будет плохой идеей.

Например, если этот класс предназначен для представления вектора в графическом пакете, и вы собираетесь выполнять то же преобразованиедля миллионов из них я мог видеть, как вы не хотели бы, чтобы вызов виртуальной функции был частью кода, который выполнял преобразование.На самом деле, вы бы хотели избежать разыменования указателей любого типа, который мог бы вам помочь.

2 голосов
/ 04 сентября 2010

Почему вообще два класса? Если классы совместно используют одни и те же данные, вы можете просто реализовать обе функции в одном классе.

class A {
private:
  double data;
public:
  double calc(){
     return data*data;
  }
   double especific(){
     return 2.0*data;
  }
   double eMoreSpecific() {
     return 23.0*data;
 }
2 голосов
/ 04 сентября 2010

Если вы не включите ни одного члена virtual и не будете разумно определять свои классы, не окажет никакого влияния на производительность в результате наследования .

Все наследство говорит "сделай этот класс таким, но с этим дополнительным материалом".Во время выполнения он ничем не отличается от того, если бы вы набрали один и тот же материал дважды.

Полагаю, вы могли бы сделать влиянием на производительность, выполнив кучу несжатых вещей в конструкторе для родителя.класс, который не нужен дочерним классам.Но ты не будешь таким глупым.Я верю в тебя.

2 голосов
/ 04 сентября 2010

Может быть, я упускаю суть, но почему бы не иметь базовый класс, который реализует все общие функции, и чисто виртуальный especific(), а затем наследовать это и заставить дочерние классы реализовывать especific(), как требуется. Сделайте элемент data защищенным.

class BaseA 
{ 
protected: 
  double data; 
public: 
  double calc(){ 
     return data*data; 
  } 
   virtual double especific() = 0;
};

class A1 : BaseA
{
   double especific()
   {
     return data * 2;
   }
};

WRT к огромному влиянию наследования на производительность ... Я думаю, что это маловероятно, если стоимость поиска vtable не будет значительной по сравнению с работой, выполняемой в теле метода, и вы делаете это в узком цикле. потребляет большую часть обработки вашего приложения.

2 голосов
/ 04 сентября 2010

имеют базовый класс со всеми общими вещами и выводят из него два класса

Как уже отмечали другие

а) это именно то, для чего было разработано наследование

b) нет никаких служебных данных

в) нигде не прячутся неприятные ошибки

Многие люди прокомментируют это и скажут «а, а как насчет хххх»; это будут действительные комментарии для расширенного и углового использования; за исключением того, что вы не собираетесь делать ни одного из них, исходя из простоты того, что вы просили.

1 голос
/ 04 сентября 2010

Проверьте шаблон стратегии

Вы могли бы попросить ваш класс взять функтор, который, в частности, вызывает. Вы можете поставить разные функторы для разных способов расчета выхода. Есть также несколько других способов реализации Стратегии.

0 голосов
/ 04 сентября 2010

проверить "шаблон наследования"

0 голосов
/ 04 сентября 2010

Есть несколько способов сделать это, многие из которых вы назвали:

  • Наследование от общего базового класса (который выполняет большую часть работы) и виртуальный especific()
  • Один класс, с двумя слегка отличающимися по имени методами especific() (или перегруженными методами)
  • Использовать специализацию шаблонов
  • Есть A и B, использовать другой класс C для выполнения большей части работы.

Могут быть и другие.

Вам нужно будет выбрать один из них на основе семантики ваших классов и приложения, илюбые другие конкретные ограничения или требования.

0 голосов
/ 04 сентября 2010

У меня такое ощущение, что паттерн моста может быть хорошим подходом для вас, поскольку кажется, что вы хотите иметь уникальные реализации для вашей общей абстракции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...