Ошибка при использовании шаблонов в C ++ - PullRequest
0 голосов
/ 18 февраля 2012

Шаблон у меня есть:

template <class T>
class Shape {
T val,val_new;
public:
Shape(T initval)
{
   val=initval;
}
T get()
{
   return val;
}
void set (T newval)
{
   val_new = newval;
}
void copy()
{
   val= val_new;
}
};

Класс для использования этого шаблона:

#include <iostream>
#include<math.h>
using namespace std;
class Rectangle
{
 private:
 Shape<TwoPoint> val;
 bool incr_called, decr_called, load_called;
 TwoPoint newval;
 public:
 Rectangle(TwoPoint i)
      : val (Shape<TwoPoint> (i)) {}     
 Shape<TwoPoint> read()
 {
   return val;
 }
 void load(TwoPoint n)
 {
   load_called=1;
   newval=n;
 }
 void increment()
 {
   incr_called=1;
 }
 void decrement()
 {
   decr_called=1;
 }
 void init()
 {
   incr_called=0;
   decr_called=0;
   load_called=0;
 }
 void actions()
 { 
   if (load_called)
       val.set(new TwoPoint(newval));
   if(incr_called && !decr_called)
       val.set((new TwoPoint(val.get())).plus(1));
   if(!incr_called && decr_called)
       val.set((new TwoPoint(val.get())).plus(-1));
 }     
 };

Класс TwoPoint определяется как:

 class TwoPoint
 {
   int width;
   int value;
   public:
    TwoPoint()
    {
      value=0;
      width=0;
     }
     TwoPoint(int v, int w)
     {
       value=v;
       width=w;
     }
     TwoPoint(const TwoPoint& t)
     {
       value= t.value;
       width= t.width;
     }
     int getWidth()
     {
       return width;
     }
     int getValue()
     {
       return value;
     }
     TwoPoint & plus(int newval)
     {
      value+=newval;
      return *this;
     }
    };

Но есть ошибки:

In member function 'void Rectangle::actions()':
error: request for member 'plus' in '(((TwoPoint*)operator new(8u)), (((*<anonymous>)
<unknown operator> TwoPoint<T>::get() [with T=TwoPoint]()), <anonymous>))', which is of non-class type 'TwoPoint*'

Есть еще одна ошибка:

In member function 'void Rectangle::actions()':
error: no pattern matching function for call to 'Shape<TwoPoint>::set(TwoPoint*)'
note: candidates are: void Shape<T>:: set<T> [with T=TwoPoint]

Есть две ошибки, когда я выполняю аналогичные операции в actions () по той же причине Может кто-нибудь объяснить, пожалуйста, эти ошибки и как их исправить? Есть ли способ повысить эффективность кода?

Ответы [ 3 ]

2 голосов
/ 18 февраля 2012

Shape::set принимает аргумент по значению, но вы создаете значение с помощью new и передаете указатель. Вам следует избегать использования new, если вам не нужен динамический объект; в этом случае вам нужно убедиться, что он удален, когда вы закончили с ним.

В этом случае вы просто хотите передать объект по значению:

 void actions()
 { 
   if (load_called)
       val.set(newval);
   if(incr_called && !decr_called)
       val.set(val.get().plus(1));
   if(!incr_called && decr_called)
       val.set(val.get().plus(-1));
 }     

Есть ли способ повысить эффективность кода?

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

Shape::set и конструктор могут принимать свои аргументы по ссылке, а Shape::get может возвращать ссылку, чтобы избежать ненужного копирования; хотя на практике компилятор, вероятно, все равно будет избегать этих копий. Кроме того, конструктор может использовать список инициализаторов, чтобы инициализировать элементы непосредственно, а не инициализировать их по умолчанию и переназначать их. Подобный код может быть несколько более эффективным в некоторых случаях:

Shape(T const & initval)      // pass by reference
  : val(initval)              // use initialiser list
{}
T const & get()               // return by reference
{
   return val;
}
void set (T const & newval)   // pass by reference
{
   val_new = newval;
}

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

2 голосов
/ 18 февраля 2012

Оператор new был очевидным виновником там. Использование автоматических переменных решает утечку памяти. Код улучшается, когда такие классы, как Shape и TwoPoint, могут передаваться как ссылки, а не как скопированные значения. Я допускаю, что мне немного скучно и немного возиться с вашим кодом, даже добавлю вывод отладки с помощью ostream. Я не могу помочь вам с логикой приложения, хотя. Я понятия не имею, почему существуют определенные конструкции, поэтому я сохранил большинство из них нетронутыми (за исключением val_new, потому что в настоящее время ничего не добавляет в код).

#include <iostream>
#include <math.h>
using namespace std;

class TwoPoint {
    int value, width;
public:
    TwoPoint() : value(0), width(0) {}
    TwoPoint(int v, int w) : value(v), width(w) {}
    TwoPoint(const TwoPoint& t) : value(t.value), width(t.width) {}
    int getWidth() { return width; }
    int getValue() { return value; }
    TwoPoint & plus(int newval) { value += newval; return *this; }
    friend ostream& operator<< (ostream& os, const TwoPoint& x);
};

template <class T> class Shape;

template <class T>
ostream& operator<< (ostream& os, const Shape<T>& x);

template <class T>
class Shape {
    T val;  // do you really need val_new?
public:
    Shape(T initval) : val(initval) {}
    T & get() { return val; }
    void set (T const & newval) { val = newval; }
    // not sure why you used and set val_new instead of val...
    friend ostream& operator<< <> (ostream& os, const Shape<T>& x);
};

class Rectangle {
private:
    Shape<TwoPoint> val;
    bool incr_called, decr_called, load_called;
    TwoPoint newval;
public:
    Rectangle(TwoPoint i) : val(Shape<TwoPoint> (i)),
        incr_called(false), decr_called(false), load_called(false) {}     
    Shape<TwoPoint> & read() { return val; }
    void load(const TwoPoint& n) { load_called = true; newval = n; }
    void increment() { incr_called = true; }
    void decrement() { decr_called = true; }
    void init() { incr_called = decr_called = load_called = 0; }
    void actions() {
        if (load_called) {
            val.set(TwoPoint(newval));
            load_called = false;  // should the flag be reset?
        }
        if(incr_called && !decr_called) {
            val.set(val.get().plus(1));
            incr_called = false;  // should the flag be reset?
        }
        if(!incr_called && decr_called) {
            val.set(val.get().plus(-1));
            decr_called = false;  // should the flag be reset?
        }
    }     
    friend ostream& operator<< (ostream& os, const Rectangle& x);
};

// added for debug printouts:
ostream& operator<< (ostream& os, const TwoPoint& x){
    os << "TwoPoint( " << x.value << ", " << x.width << " )";
    return os;
}
template <class T>
ostream& operator<< (ostream& os, const Shape<T>& x){
    os << "Shape( " << x.val << " )";
    return os;
}
ostream& operator<< (ostream& os, const Rectangle& x){
    os << "Rectangle( " << x.val 
    << (x.load_called ? ", load_called" : "")
    << (x.incr_called ? ", incr_called" : "")
    << (x.decr_called ? ", decr_called" : "")
    << " )";
    return os;
}

int main() {
    TwoPoint tp(800, 300);
    cout << "Creating a Rectangle using " << tp << endl;
    Rectangle r(tp);
    cout << r << endl;
    r.load(TwoPoint(100, 200));
    cout << r << endl;
    r.actions();
    cout << r << endl;
    r.increment();
    cout << r << endl;
    r.actions();
    cout << r << endl;
    r.decrement();
    cout << r << endl;
    r.actions();
    cout << r << endl;
    return 0;
}

И вывод программы:

Creating a Rectangle using TwoPoint( 800, 300 )
Rectangle( Shape( TwoPoint( 800, 300 ) ) )
Rectangle( Shape( TwoPoint( 800, 300 ) ), load_called )
Rectangle( Shape( TwoPoint( 100, 200 ) ) )
Rectangle( Shape( TwoPoint( 100, 200 ) ), incr_called )
Rectangle( Shape( TwoPoint( 101, 200 ) ) )
Rectangle( Shape( TwoPoint( 101, 200 ) ), decr_called )
Rectangle( Shape( TwoPoint( 100, 200 ) ) )

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

1 голос
/ 18 февраля 2012

У вас есть это:

(new TwoPoint(val.get())).plus(1)

new возвращает указатель на TwoPoint, поэтому вы должны использовать -> вместо . для доступа к функциям-членам.

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

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