在C ++中使用模板时出错

时间:2012-02-18 11:42:42

标签: c++ oop templates

我拥有的模板是:

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 个答案:

答案 0 :(得分:2)

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;
}

但总的来说,专注于使代码正确和可读,以及选择有效的算法;如果他们被证明是一个瓶颈,他们只会担心效率低下。

答案 1 :(得分:2)

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 ) ) )

我希望这个调试内容在进一步开发这个应用程序时证明是有用的。

答案 2 :(得分:1)

你有这个:

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

new会返回指向TwoPoint的指针,因此您必须使用->代替.来访问成员函数。

但是,如果你这样做,你会在一般情况下得到内存泄漏。我建议重新考虑你的设计,这样你就不需要动态分配东西了。