0

我需要创建一个通用的对象载体类。我想出了一些简单的东西

template<typename T>
class ObjectCarrier
{

public:
    const T& item() const
    {
        return item_;
    }

    void setItem(T& item)
    {
        item_ = item;
    }

private:
    T item_;
};

T有默认构造函数(无参数)时,这很有效。T当有参数化的构造函数时,事情变得复杂了。所以我重写了这个类

template<typename T>
class ObjectCarrier
{

public:
    const T& item() const
    {
        return *item_;
    }

    void setItem(T& item)
    {
        item_ = new T ( item );
    }

private:
    T* item_;
};

item_将变量更改为T*并使用 的复制构造函数创建了一个新实例T。这再次运行良好,直到T是指针类型。我的意思是ObjectCarrier<Foo*>不会工作。

我想知道如何设计这个类,以便它适用于几乎所有类型的类型。我想我可能需要创建一个traits专门用于指针的类型。但不幸的是,我无法完成这项工作。

任何帮助都会很棒。

4

5 回答 5

2

上面的方法太复杂了。保持简单,只需使用模板构造函数解决构造函数 arg 问题。不要使用指针,它们会造成对象生命周期和复制问题。

这是我经常使用的一个实现。模板构造函数会将事物的参数直接转发到嵌套对象,这很方便。运算符 T& 值允许您传递carrier<T>给采用类型 T 的函数,而无需进行昂贵的复制。您可以使用此代码包装最多需要两个参数的对象。

/* A wrapper of type T */
template <typename T>
struct carrier {

   carrier() {}
   template <typename A1> carrier(const A1& a1) : value(a1) {}
   template <typename A1, typename A2> carrier(const A1& a1, const A2& a2) : value(a1, a2) {}

   operator T&() { return value; }
   operator const T&() const { return value; }

   T value;
};

你可以像这样使用它:

const carrier<point> p1(10,10);   // make p1 const to stop people changing it
showPoint(p1);                    // calls a function that expects a point,
showPoint(p1.value);              // access the point directly
于 2010-01-20T06:35:58.227 回答
0

有可能通过值来保存对象,但仍然可以使用placement new 来延迟其构造,如下所示:

#include <iostream>
#include <cassert>

template <class T>
class ObjectCarrier
{
public:
    ObjectCarrier(): ref(0) {}
    ObjectCarrier(const ObjectCarrier& other): ref(0)
    {
        set_data(other.ref);
    }
    ~ObjectCarrier()
    {
        clear();
    }
    const ObjectCarrier& operator = (const ObjectCarrier& other)
    {
        if (other.empty())
            clear();
        else
            set_data(other.ref);
        return *this;
    }
    void set(const T& value)
    {
        set_value(value);
    }
    const T& get() const
    {
        assert(!empty() && "No object being carried");
        return *ref;
    }
    bool empty() const
    {
        return ref == 0;
    }
    void clear()
    {
        if (!empty()) {
            ref->~T();
            ref = 0;
        }
    }
private:
    char data[sizeof(T)];
    T* ref;
    void set_value(const T& value)
    {
        if (!empty()) {
            *ref = value;
        }
        else {
            ref = new (data) T(value);
        }
    }
    void set_data(const T* value)
    {
        if (value) {
            set_value(*value);
        }
    }
};

int main()
{
    ObjectCarrier<int> i;
    ObjectCarrier<int> j(i);
    i = j;
    i.set(10);
    std::cout << i.get() << '\n';
    j = i;
    i.set(20);
    std::cout << i.get() << ' ' << j.get() << ' ' << ObjectCarrier<int>(i).get() << '\n';
}

但是,我会有点质疑这个类的用处。也许它的唯一目的是充当Boost.Optional

但是如果你不希望类不能保存一个值,只需给它一个参数化的构造函数:

template<typename T>
class ObjectCarrier
{

public:
    ObjectCarrier(const T& value = T()):
        item_(value)
    {
    }
    const T& item() const
    {
        return item_;
    }

    void setItem(T& item)
    {
        item_ = item;
    }

private:
    T item_;
};

(只是这个类看起来相当无用,除非作为代码的外观,期望变量具有 item 和 setItem 方法,而不是,比如说,赋值运算符。)

于 2009-11-08T11:18:53.907 回答
0

您可以对类型使用模板特化T*并将方法重写为套件指针。您可以执行以下操作:

template<typename T>
class ObjectCarrier<T*>
{
    public:
    const T* item() const
    {
        return item_;
    }

    void setItem(T* item)
    {
        item_ = item;
    }

private:
    T* item_;

};
于 2009-11-08T05:08:34.550 回答
0

boost::optional 做了与此非常相似的事情(也 boost::any,但没关系)。您可以在以下网址查看其实现方式:http ://cplusplus.co.il/2009/12/04/boost-optional-and-its-internals/ ,不用担心 - 它非常简单。

于 2009-12-26T11:04:22.787 回答
0

有一个可能与此相关的设计模式 - Memento。

有点跑题了,但请记住,一旦您开始在类中新建对象,您就需要一种管理内存的方法。我建议至少使用 std::auto_ptr 。在使用 std::auto_ptr 时,您还需要提供一个复制构造函数和一个赋值运算符。

于 2009-11-08T06:52:55.633 回答