2015-11-26 2 views
3

EDITИнтерфейсы, которые используют себя в методах

Основная идея заключалась в создании интерфейса, который позволяет добавлять новые типы элементов. Например, добавьте Strings, вычисляя его расстояние с помощью алгоритма «X». Вот почему я думаю, что шаблоны не могут быть правильным ответом.

Я изменил определение функции по расстоянию в классе Element, и теперь у него есть реализация.

class Element : public Object 
{ 
... 
    virtual float distance(Element *other){return INFINITE;}; 
... 
} 

Для векторного класса его же изменение:

class Vector : public Element 
{ 
... 
    virtual float distance(Element *other); 
... 
} 

его реализация:

float Vector::distance(Element *other) 
{ 
    if(other->getClass() != this->getClass()) return INFINITE;//this came from Object class 
    Vector *n_other = dynamic_cast<Vector*>(other); 
    float result = this->L2D(*this,*n_other); 
    return result; 
} 

OLD

хорошо, что я пытаюсь сделать интерфейс в C++ так что дочерние классы могли бы написать этот метод.

В этом случае расстояние представляет собой значение, представляющее, как близкие (похожие) два элемента.

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

//Element.h 
class Element 
{ 
    virtual float distance(Element const&, Element const&)=0; 
};` 

тогда у меня есть класс Vector

//Vector.h 
#include "Element.h" 
class Vector: public Element 
{ 
    float distance(Vector const&, Vector const&);//(?) 
}; 

И внедрение

#include "Vector.h" 
float Vector::distance(Element const &a, Element const &b) 
{ 
    return Vector::L2D(a,b);//Euclidean distance 
} 

Ну моя проблема в том, как я могу это сделать, потому что я не нашел пример для этого проблема. Я не совсем уверен, если вы понимаете, что я пытаюсь сделать ... Надеюсь. Спасибо всем.

+0

Детские классы не пишут методы, они реализуют их. Почему метод расстояния принимает два объекта? Я бы ожидал, что это займет один или будет статичным. – user463035818

+0

и кстати вопрос не совсем понятен (по крайней мере мне). Как вы можете что-то сделать? Вы не найдете пример какой проблемы? Я не вижу никаких проблем. – user463035818

+0

Я думаю, что теперь я медленно начинаю понимать, в чем вопрос ... – user463035818

ответ

1

Что я вижу из вашего базового класса Element, так это то, что это абстрактный тип, поскольку хотя бы один из его методов объявлен как purely virtual. Это означает две вещи: во-первых, вы не можете создать объект типа Element, а во-вторых, все унаследованные классы должны реализовывать любые функции, объявленные как pure virtual.

В вашем базовом классе у вас есть это в качестве своей декларации:

virtual float distance(Element const&, Element const&)=0; 

и в производном классе у вас есть это в качестве своей декларации:

float distance(Vector const&, Vector const&);//(?) 

и в реализации производного класса у вас есть это :

float Vector::distance(Element const &a, Element const &b) { 
    return Vector::L2D(a,b);//Euclidean distance 
} 

Базовый класс заявляет, что эта чистая виртуальная функция tha t весь производный класс должен реализовать, должен возвращать float и должен принимать две ссылки const на тип элемента. Однако в вашем унаследованном классе в его декларации указывается иначе: он заявляет, что эта функция возвращает значение float, которое не является проблемой, но его типы параметров - это то, что объявляется как взятие двух ссылок на константу типа Vector. Если вы используете MS Visual Studio 2012 или более поздней версии, вы можете попробовать сделать это: добавить ключевое слово override после объявления функции в унаследованной классе, так что ваша унаследовали декларация будет выглядеть следующим образом:

float distance(Vector const&, Vector const&) override; 

Затем попробуйте скомпилировать и см., если вы получаете какие-либо ошибки компилятора, сборки или ссылки.

Следующим шагом было бы изменить декларацию и определение производного класса в соответствии с объявлением базового класса чистой виртуальной подписи. После этого ваше объявление производной функции будет выглядеть так:

float distance(Element const&, Element const&) override; 

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

Element.h

#ifndef ELEMENT_H 
#define ELEMENT_H 

class Element { 
public: 
    virtual float distance(Element const&, Element const& ) = 0;  
}; // Element 

#endif // ELEMENT_H 

Element.каст

#include "stdafx.h" 
#include "Element.h" 

// ---------------------------------------------------------------------------- 
// distance() 
float Element::distance(Element const&, Element const&) { 
    return 0; 
} // distance 

vector.h

#ifndef VECTOR_H 
#define VECTOR_H 

#include "Element.h" 

class Vector : public Element { 
public: 
    float distance(Element const&, Element const&) override;  
}; // Vector 

#endif // VECTOR_H 

Vector.cpp

#include "stdafx.h" 
#include "Vector.h" 

// ---------------------------------------------------------------------------- 
// distance() 
float Vector::distance(Element const&, Element const&) { 
    return 1; 
} // distance 

main.cpp

#include "stdafx.h" 
#include "Vector.h" 

int main() { 
    float val = 0; 

    Vector v1; 
    Vector v2; 
    Vector v3; 
    val = v3.distance(v1, v2); 

    std::cout << val << std::endl; 

    std::cout << "Press any key to quit" << std::endl; 
    _getch(); 

    return 0; 
} // main 

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

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

Если вы заметили здесь, декларация ожидает два const& в типе Element объекта, но когда я вызываю метод, который я передаю в двух объявлены переменные типов или экземпляров Vector объекта. Это работает, потому что объекты Vector наследуются от типа Element. Также, если вы посмотрите на выходное значение, напечатанное значение равно 1, а не 0. Это то, что вы хотите, когда вы пытаетесь сделать override объявление функции базового класса.

Element::distance() возвращает 0 - Это не может быть названы, поскольку она является чисто виртуальный метод вызывает базовый класс абстрактным

Vector::distance() возвращается 1 - Это будет называться на векторном объекте.

Возможно, это поможет вам достичь того, что вам нужно.

2

То, о чем вы просите, называется argument covariance. А именно, измените аргумент переопределяющего метода с изменением наследования. Это интуитивно имеет смысл, но может быть проблемой безопасности типа корпуса. Предположим, что это возможно, и ваш код скомпилирован. Тогда что бы тут произошло?

Element* e = new Vector(); 
e->distance(Element(), Element()); // but Vector::distance expects an Element! 

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

Ваших вариантов таким образом:

  1. Придерживайтесь основной подпись, а также использовать dynamic_cast для (попробуйте) обратное приведение аргументов на наиважнейшем методе
  2. Избегайте чисто виртуальную функцию, и просто каждый класс определить свой собственный метод, используя соответствующие типы аргументов.
  3. Такие образцы, как double-dispatch, иногда могут пригодиться в таких случаях.

Обратите внимание, что использование шаблонов не поможет вам здесь - виртуальная функция не может быть шаблоном.

+0

функции-члены виртуального шаблона невозможны, но классы шаблонов могут иметь виртуальные функции (см. [Здесь] (http://stackoverflow.com/a/8919588/4117728)) – user463035818

+0

@ tobi303 уверен, что они могут, но шаблон не будет полезный как интерфейс. – eran

+0

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

0

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

#include <iostream> 

template <typename T> 
struct DistInterf { 
    virtual double distance(T other)=0; 
}; 

struct A : DistInterf<A> { 
    double distance(A other){ 
     return 2; 
    } 
}; 

int main() { 
    A t,t2; 
    std::cout << t.distance(t2) << std::endl; 
    return 0; 
} 

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

Я уже упомянул в комментарии: Функция расстояния должна быть либо статической, либо принимать только один параметр, иначе имхо имеет мало смысла.

PS: Существует один случай использования я могу думать:

template<typename T> 
void foo(T t1,T t2){ 
    std::cout << t1.distance(t2) << std::endl; 
} 

Вы можете пройти любой тип, реализующий выше interace в качестве параметра шаблона.

Смежные вопросы