RE: Hidden Columns in Gtk::TreeView, making life easier.



On Wed, 2006-02-22 at 15:24, Murray Cumming wrote:
On Wed, 2006-02-22 at 15:39 -0500, Huston, Bob wrote:
> I have done this exact thing, I think the tree view will only allow
> a certain number of types to be columns, the way I got around what you
> are
> seeing is add the column as a void *, then type cast a ptr to my class
> to go into the column.

That shouldn't be necessary. Any type that has a copy constructor can be
used. And if it doesn't have a copy constructor, you can use it via its
specific pointer type, or via a smartpointer, such as boost's shared
ptr.
Indeed, that an object have a copy constructor *is* all that is necessary to add(object) to Gtk::TreeModelColumn. But one might encounter unexpected results elsewhere in one's program if one does not *also* provide a well-crafted assignment operator, from which the copy-constructor may itself be easily implemented. (An example will follow.)

To keep life simple, I distinguish two types of C++ classes: those that will have but a single instance throughout my program, and those that will have more. Single-instance classes are usually (not always) complicated enough to require a non-default constructor; for these classes I will declare a default constructor as well, but not define it. This will inhibit the compiler from silently generating a default constructor behind my back, and subsequently give link errors of the kind Nathan saw if I ever mistakenly try to make another copy of such a single-instance object, such as by inserting such an object into a multiple-instance container, whether that container be Gtk::TreeStore, GTK::ListStore, or any of the std:: STL containers.

All the rest of my classes -- by far most of them -- I intend to have multiple instances and eventually be inserted into various templatized containers. As a matter of programming habit, I *always* write such classes in what is sometimes called the "Orthodox Canonical Form," which for some class X is characterized by the presence of the following four members:
    * A default constructor X::X()
    * A copy constructor    X::X(const X& rhs)
    * An assignment operator X& operator=(const X& rhs)
    * A destructor X::~X()
See e.g. James O. Coplien "Advanced C++ Programming Styles and Idioms" 1992 AT&T Bell Labs, page 44. This "Orthodox Canonical Form" idiom pervades all of OO programming, so you will certainly find it discussed elsewhere. In particular, the STL assumes that all classes used as templates for an STL container obey this idiom, that is, have properly implemented the above four methods. So do the Gtk:: containers.

It is not that hard, the most frustrating part (for me) being remembering to mention *all" class data members in the assignment operator. The two-penny tour:

class X{
private:
    int a;
    int b;
public:
    X() : a(0), b(-1){};
    ~X(){};  // in this case X has nothing to deallocate or destroy
    X& operator=(const X & rhs){
        if(this != &rhs){
          a = rhs.a;  // this list can be lengthy, don't miss anything!
          b = rhs.b;
        }
        return *this;
    };
    X(const X & rhs){ *this = rhs;};
};

Note the signature and semantics of operator=(). It *must* return a non-const reference to the object being assigned (return *this) so that f'rinstance if q, r, and s are objects of class X, the statement q = r = s; will compile and make sense. Also note the self assignment test if(this != &rhs). This test must be made so that the trivial assignment q = q;  remains trivial, and not have untoward side-effects...

And last, note the clever one-line  implementation of the copy constructor in terms of operator=(). I, at least, use it so much that I sure *hope* its clever, and that someone will kindly inform me if otherwise :-)

Hope this helps!

Ed

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]