0

Can the line in main work? Maybe other operators? Some suggestions? I think the order of operations is the problem here. Is it a must to use b.addA("P"); b.R("P").ref(b.R("P")); ?

I want to add references from an object to others and make relations between objects, like a database model.

#include <iostream>
#include <vector>
#include <string>

class A;
class B;

class A{
    std::string _name;
    std::vector<A*> _refs;
public:
    A(std::string="");
    A& ref(A&);
    std::string name() const;
};

class B{
    std::string _name;
    std::vector<A> _as;
public:
    B(std::string="");
    A& addA(std::string);
    A& R(std::string);
};

A::A(std::string nm){
    _name=nm;
}

A& A::ref(A &a){
    for(int i=0; i<_refs.size(); i++)
        if(_refs[i]==&a)
            return a;
    _refs.push_back(&a);
    return a;
}

std::string A::name() const{
    return _name;
}

B::B(std::string nm){
    _name=nm;
}

A& B::addA(std::string nm){
    for(int i=0; i<_as.size(); i++)
        if(_as[i].name()==nm)
            return _as[i];
    _as.push_back(A(nm));
    return _as[_as.size()-1];
}

A& B::R(std::string nm){
    for(int i=0; i<_as.size(); i++)
        if(_as[i].name()==nm)
            return _as[i];
    throw std::string("invaild A");
}

int main(){
    B b;
    b.addA("P").ref(b.R("P"));
    return 0;
}
Adrian Munteanu
  • 124
  • 1
  • 9
  • (among other things) I think this is wrong: `_as.push_back(A::A(nm));`. Perhaps you meant `_as.push_back(A(nm));` – Mihai Todor Sep 22 '12 at 12:05
  • @MihaiTodor: I think this is ok, because I want to store in my vector of type A named _as my "sub-objects" – Adrian Munteanu Sep 22 '12 at 12:13
  • You can't / shouldn't call a classes' constructor directly, even though VS2010 seems to allow it. After correcting this, I still get a strange error in GCC, but I'm not sure why. – Mihai Todor Sep 22 '12 at 12:16
  • @MihaiTodor: I would have called A(nm); in order to create an object of type A, but it would take the B::A(std::string) – Adrian Munteanu Sep 22 '12 at 12:18
  • So, yeah, it turns out that [it's illegal to have a class method sharing the same name as a class in the same context](http://stackoverflow.com/a/12187709/1174378). And you are a victim of this limitation. GCC is smart enough to prohibit you from doing this. – Mihai Todor Sep 22 '12 at 12:20
  • I think I can add friendship between classes, store a pointer to B in A, and make a function ref(std::string) in A that calls B::R through the pointer of B in A and the call would be b.addA("P").ref("P"); and this works – Adrian Munteanu Sep 22 '12 at 13:17

2 Answers2

2

Can the line in main work?

Sure. There are only two operators in play here, function call and reference (the dot operator). You would have a problem if association was right to left or if function call had precedence over reference. That isn't the case. Function call and reference have the same precedence and the association is left to right. That's just what you want.

There is a problem with your code, however. It's the member function B::A. Within the context of class B, this changes the meaning of A from class A to member function B::A(std::string). Your code fails to compile on multiple compilers for me, but it does compile with clang 3.1. That looks like a clang bug to me. (Addendum: That this does compile with clang is OK because the rule that is being violated is one of those nasty "no diagnostic is required" rules.) Your code is illegal; it (ideally) should fail to compile.

A better name for that function is findA. This name doesn't collide with the class name and it makes the code self documenting.

Aside: You might want to think of having that function return a pointer rather than a reference. Exceptions should be used for exceptional events (i.e., errors). Is the fact that (for example) "Foo" is not represented in your vector truly worthy of throwing an exception?

David Hammen
  • 32,454
  • 9
  • 60
  • 108
  • changed A& B::A(std::string) to A& B::R(std::string), the question remains... :( – Adrian Munteanu Sep 22 '12 at 12:31
  • It also compiles on VS2010, but it's still [illegal](http://stackoverflow.com/a/12187709/1174378). – Mihai Todor Sep 22 '12 at 12:31
  • I want to return refernce in order to write a chained instruction, like the one in maine. – Adrian Munteanu Sep 22 '12 at 12:37
  • @Adrian Dude, line `b.addA("P").ref(b.R("P"));` will evaluate `b.R("P")` first. I'm not sure what you're trying to achieve here, but if you want to execute `b.R("P")` after `b.addA`, then this is not the way to do it. – Mihai Todor Sep 22 '12 at 12:38
  • @MihaiTodor: I also noticed that, but I want to do something like that if it is possible. For example if I can use other operator to evaluate from left to right like it's written... – Adrian Munteanu Sep 22 '12 at 12:42
0

To begin with the line in main will surely work. Now how that happens is a question you would be interested in? When you call the addA("P") it creates the object of class A and returns it by reference, now this object of A calls its member fn ref(A&), as you can see you need to pass an object of A by reference to this function which are doing by calling b.R("P") which in itself returns reference to just now added object with string "P". Now you have

A'.ref(A")

where A' A" are referenced object returned by two different fn of B class(bydway in this case A'A" will be the same).

The above call will return another object of class A by reference which you can assign to any other instance of A like

A t; t = b.addA("P").ref(b.R("P"));

You are just doing chained function call and by returning object by references you make sure that nothing is going on in temporary variables which you might lose. Hope I have answered your question.

grv
  • 1,013
  • 2
  • 12
  • 19
  • The problem is that the b.R("P") is called first. If I create friendship between classes and make ref(std::string) to search through a pointer to b it has the wanted result. More detailed, in A I can have B* _myb and call in ref(std::string nm) _myb->R(nm) to find that object of type A and add it to the refs, then the call to ref would be like b.addA("P").ref("P"). This works. – Adrian Munteanu Sep 22 '12 at 17:27