0

I'm learning C++ from a Java background and here is a problem I just met:

Let's say I have a class named A. I use a wrapper called AWrapper. I want A has a link to its wrapper, not just AWrapper but any wrapper. So in Java, I can implement this as below:

public class A {
    Object tag;
    Object getTag() {
        return tag;
    }

    void setTag(Object tag) {
        this.tag = tag;
    }
}

and its wrapper:

public class AWrapper {
    A a;
    public AWrapper(A a) {
        this.a = a;
        a.setTag(this);
    }
}

But in C++, everything is not that simple. First, C++ doesn't have anything as Object in Java. Second, if I don't use Object but AWrapper as return in the getTag(), I will have circular dependency problem. Can anyone show me how to solve this?

Really sorry if my question is dumb, my C++ skill is still poor so any help will be appreciated!

Anh Tuan
  • 1,728
  • 1
  • 13
  • 25
  • 8
    You're thinking about this the wrong way. C++ *is* simple, but it's *different*. Forget how you do things in Java, and start learning C++ the C++ way. – Kerrek SB Oct 29 '12 at 02:39
  • 2
    Welcome to the complex-and-has-many-hidden-details-but-can't-get-out-'cause-it's-just-darn-the-best language named C++ friend. – Mark Garcia Oct 29 '12 at 02:42
  • 1
    Java's objects all implicitly inherit from Object. You could, in theory, make everything you personally are working with inherit from some root class (like Object). Next, Java has full on automatic garbage collection, while C++ ... well, in C++ few people find anything beyond reference counting worthwhile: in C++, you need to manage your objects lifetime, and not leave it to the framework to handle usually. Another thing you'll have to get used to is the difference between INSTANCE of an object, and POINTERS to an object: in Java, every non-trivial object was a POINTER basically. – Yakk - Adam Nevraumont Oct 29 '12 at 02:45
  • 2
    C++ is completely different from Java. Forget everything you’ve learned about OOP and Java and [pick up a good book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). Also forget design patterns anyway. –  Oct 29 '12 at 02:46
  • 1
    As for circular dependencies, forward declarations (class A;, and class AWrapper;) let you have pointers to the classes (without using them). You can then move implementations to a place where you can see both interfaces. Despite this, I'd advise against doing it... in general, in C++ you state (with a type) what kind of interacting you will have with a variable. How will A interact with the tag? That should define the class type of the tag. – Yakk - Adam Nevraumont Oct 29 '12 at 02:47
  • 2
    @KerrekSB Can you show me the C++ way to solve this problem? My purpose is to make A class has access to its wrapper – Anh Tuan Oct 29 '12 at 03:06
  • 1
    @AnhTuan: Step back ten paces and rethink the design. Chances are you don't actually need a wrapper. – Kerrek SB Oct 29 '12 at 03:15
  • In C++, you can have multiple inheritance. If you are setting tag ("has a" relationship) just to avoid the multiple inheritance, then think again. – iammilind Oct 29 '12 at 03:20
  • FYI, http://stackoverflow.com/questions/4233123/what-is-the-c-equivalent-of-java-lang-object-x-new-foo – Khan Oct 29 '12 at 13:13

2 Answers2

2

I think all you need is a void pointer - this compiles, but I haven't played around with it:

class A
{
public:
    void *tag;
    virtual void *getTag()
    {
        return tag;
    }

    virtual void setTag(void *tag)
    {
        this->tag = tag;
    }
};

class AWrapper
{
public:
    A *a;
    AWrapper(A *a)
    {
        this->a = a;
        a->setTag(this);
    }
};
Dave Doknjas
  • 6,394
  • 1
  • 15
  • 28
  • Thanks for your answer! I'll try it and let you know the result. But I've one more question: can I use shared pointer instead of pointer in this case? More specifically, is shared pointer can wrap void pointer? – Anh Tuan Oct 29 '12 at 03:04
  • Apparently - I haven't used it myself though - http://stackoverflow.com/questions/4807286/shared-void-pointers-why-does-this-work – Dave Doknjas Oct 29 '12 at 03:06
  • 4
    I would have used something less painful, such as `boost::any`. Using `void *` raises some uncomfortable lifetime issues. – Etienne de Martel Oct 29 '12 at 03:16
  • Even better - forgot all about boost::any ! – Dave Doknjas Oct 29 '12 at 03:22
  • @EtiennedeMartel Can you write your answer for my problem? I'll accept it if it works :) – Anh Tuan Oct 29 '12 at 03:29
  • @Etienne: How does it raise any lifetime issues? It's just a plain ol' observer. `boost::any` would mean that `A` owns its wrapper, which would be just wrong. – Xeo Oct 29 '12 at 06:15
1

I have no idea what your use case is, so I have no idea if this will solve your problem (if you actually have one):

template<typename TagT>
class A
{
    TagT* ptag_;
public:
    A() :ptag_() {}

    TagT& getTag() { return *ptag_; }

    void setTag(TagT& tag) { ptag_ = &tag; }
};



class AWrapper
{
    A<AWrapper> a_;
public:
    AWrapper(A<AWrapper> a) {
        a_ = a;
        a_.setTag(this);
    }
};

In this case though, the A class is not actually a class. It is a class template. Each type of A will only be able to store one type of tag. So, A<X> will only be able to have a tag of type X, and A<Z> will only be able to have a tag of type Z. I don't know if this restriction suits your requirements, because your requirements are entirely unclear to me.

Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
  • Thank you! It looks promising but unfortunately it doesn't fit into my design. Anyway, it gives me an idea how to deal with my problem. – Anh Tuan Oct 30 '12 at 04:36