namespaces, linkage error, operator overloading

Discussion in 'C++' started by jakester, Apr 14, 2007.

  1. jakester

    jakester Guest

    I am using Visual C++ 2007 to build the code below. I keep getting
    linkage error. Could someone please tell me what I am doing wrong? The
    code works until I start using namespace for my objects.

    Error 1 error LNK2019: unresolved external symbol "class
    std::basic_ostream<char,struct std::char_traits<char> > & __cdecl
    graph::eek:perator<<(class std::basic_ostream<char,struct
    std::char_traits<char> > &,class graph::Node &)" (??6graph@@YAAAV?
    $basic_ostream@DU?$char_traits@D@std@@@std@@AAV12@AAVNode@0@@Z)
    referenced in function _main Program.obj

    //Node.h
    #ifndef NODE_H
    #define NODE_H

    #include <string>
    #include <iostream>

    using std::eek:stream;
    using std::string;

    namespace graph {
    class Node
    {
    friend ostream &operator<<(ostream &, Node &);
    public:
    Node(void);
    Node(const string id);
    ~Node(void);

    string getId() const;
    void setId(const string &);
    private:
    string id;
    };
    }

    #endif

    //Node.cpp
    #include "Node.h"

    using graph::Node;

    namespace graph {
    Node::Node(void)
    {
    }


    Node::Node(const string id) {
    }

    Node::~Node(void)
    {
    }

    string Node::getId() const {
    return id;
    }

    void Node::setId(const string &id) {
    this->id = id;
    }
    }

    ostream &operator<<(ostream &output, Node &node) {
    output << node.getId();
    return output;
    }

    //Program.cpp
    #include "Node.h"

    using graph::Node;
    using std::cout;
    using std::endl;

    int main() {
    Node a("a");
    Node b("b");

    cout << a << " and " << b << endl;
    }
    jakester, Apr 14, 2007
    #1
    1. Advertising

  2. jakester

    twomers Guest

    #ifndef NODE_H
    #define NODE_H

    #include <string>
    #include <iostream>

    using std::eek:stream;
    using std::string;

    namespace graph {
    class Node
    {
    public:
    friend ostream &operator<<(ostream &, Node &);
    Node(void);
    Node(const string id);
    ~Node(void);

    string getId() const;
    void setId(const string &);
    private:
    string id;
    };

    }

    #endif

    //Node.cpp

    using graph::Node;

    namespace graph {
    Node::Node(void)
    {
    }

    Node::Node(const string id) {
    }

    Node::~Node(void)
    {
    }

    string Node::getId() const {
    return id;
    }

    void Node::setId(const string &id) {
    this->id = id;
    }

    ostream &operator<<(ostream &output, Node &node) {
    output << node.getId();
    return output;
    }
    }



    //Program.cpp

    using graph::Node;
    using std::cout;
    using std::endl;

    int main() {
    Node a("a");
    Node b("b");

    cout << a << " and " << b << endl;
    }

    Fixes it.
    twomers, Apr 14, 2007
    #2
    1. Advertising

  3. jakester

    jakester Guest

    Could you help to explain what happens by declaring the operator<<
    inside public as opposed to outside? I am using C++, How to Program by
    Deitel/Deitel (3rd edition) as a reference. On page 528, they talk
    about implementation of operator overloading as member versus non-
    member functions. This is their guidance:

    1. (), [], ->, or any assignment operator must be implemented as
    member function
    2. when an operator function is implemented as a member function, the
    leftmost operand must be a class object of the operator's class ... if
    the left operand must be an object of a different class or built-in
    type, this operator function must be implemented as a non-member
    function.

    They specifically state that << and >> operators should be implemented
    as non-member functions. Doesn't this mean outside public (as I had in
    the original post)?

    Thanks.

    On Apr 14, 5:14 pm, "twomers" <> wrote:
    > #ifndef NODE_H
    > #define NODE_H
    >
    > #include <string>
    > #include <iostream>
    >
    > using std::eek:stream;
    > using std::string;
    >
    > namespace graph {
    > class Node
    > {
    > public:
    > friend ostream &operator<<(ostream &, Node &);
    > Node(void);
    > Node(const string id);
    > ~Node(void);
    >
    > string getId() const;
    > void setId(const string &);
    > private:
    > string id;
    > };
    >
    > }
    >
    > #endif
    >
    > //Node.cpp
    >
    > using graph::Node;
    >
    > namespace graph {
    > Node::Node(void)
    > {
    > }
    >
    > Node::Node(const string id) {
    > }
    >
    > Node::~Node(void)
    > {
    > }
    >
    > string Node::getId() const {
    > return id;
    > }
    >
    > void Node::setId(const string &id) {
    > this->id = id;
    > }
    >
    > ostream &operator<<(ostream &output, Node &node) {
    > output << node.getId();
    > return output;
    > }
    >
    > }
    >
    > //Program.cpp
    >
    > using graph::Node;
    > using std::cout;
    > using std::endl;
    >
    > int main() {
    > Node a("a");
    > Node b("b");
    >
    > cout << a << " and " << b << endl;
    >
    > }
    >
    > Fixes it.
    jakester, Apr 14, 2007
    #3
  4. jakester wrote:
    > I am using Visual C++ 2007 to build the code below. I keep getting
    > linkage error. Could someone please tell me what I am doing wrong? The
    > code works until I start using namespace for my objects.


    In this case, I'm not sure the compiler is totally compliant, however, I
    don't think the error is the issue.

    >
    > Error 1 error LNK2019: unresolved external symbol "class
    > std::basic_ostream<char,struct std::char_traits<char> > & __cdecl
    > graph::eek:perator<<(class std::basic_ostream<char,struct

    ^^^^^^^^^^^^^^^^^^

    Notice the graph:

    > std::char_traits<char> > &,class graph::Node &)" (??6graph@@YAAAV?
    > $basic_ostream@DU?$char_traits@D@std@@@std@@AAV12@AAVNode@0@@Z)
    > referenced in function _main Program.obj
    >
    > //Node.h
    > #ifndef NODE_H
    > #define NODE_H
    >
    > #include <string>
    > #include <iostream>
    >
    > using std::eek:stream;
    > using std::string;


    notice, this is outside the graph: - In this case I suggest you don't do
    this using in a header.

    >
    > namespace graph {



    > class Node
    > {
    > friend ostream &operator<<(ostream &, Node &);


    OK - friend in this case injects a declaration into the enclosing
    namespace, i.e. graph. But, this probably doesn't do what you think you
    want it to do since operator<< is a template not a straight function.

    BTW - you really want a const Node &

    > public:
    > Node(void);
    > Node(const string id);
    > ~Node(void);
    >
    > string getId() const;


    // don't have to do this - but it's prolly a good idea to return a
    // const std::string & here.

    > void setId(const string &);
    > private:
    > string id;
    > };
    > }
    >
    > #endif
    >
    > //Node.cpp
    > #include "Node.h"
    >
    > using graph::Node;
    >
    > namespace graph {
    > Node::Node(void)
    > {
    > }
    >
    >
    > Node::Node(const string id) {
    > }
    >
    > Node::~Node(void)
    > {
    > }
    >
    > string Node::getId() const {
    > return id;
    > }
    >
    > void Node::setId(const string &id) {
    > this->id = id;
    > }
    > }
    >


    This is being defined in the global namespace.

    > ostream &operator<<(ostream &output, Node &node) {
    > output << node.getId();
    > return output;
    > }
    >
    > //Program.cpp
    > #include "Node.h"
    >
    > using graph::Node;
    > using std::cout;
    > using std::endl;
    >
    > int main() {
    > Node a("a");
    > Node b("b");
    >
    > cout << a << " and " << b << endl;
    > }
    >



    when I compile your code on gcc I get this :

    friendop1.cpp: In function 'int main()':
    friendop1.cpp:69: error: ambiguous overload for 'operator<<' in
    'std::cout << a'
    friendop1.cpp:53: note: candidates are: std::eek:stream&
    operator<<(std::eek:stream&, graph::Node&)
    friendop1.cpp:11: note: std::eek:stream&
    graph::eek:perator<<(std::eek:stream&, graph::Node&)

    Which is more like what I expect but I don't think that's totally right
    either - not sure but it is irrelevant.

    The code at the end of this posting shows somthing that does compile and
    run on gcc (probably will also on VC).

    Some people will object to adding things to the std namespace some
    people will say that this is specifically allowed. I've seen some
    compilers that won't work too well if it's not in the std:: namespace so
    that's why I put it there but it may have been a buggy compiler.


    --------------------------------------------------------------
    #include <iostream>
    #include <string>


    namespace graph {
    class Node;
    }

    namespace std {

    template<
    typename i_char_type,
    class i_traits
    >

    basic_ostream<i_char_type, i_traits>& operator << (
    basic_ostream<i_char_type, i_traits> & i_ostream,
    const graph::Node & i_value
    );

    } // end namespace

    namespace graph {
    class Node
    {
    // friend decl
    template<
    typename i_char_type,
    class i_traits
    >

    friend
    std::basic_ostream<i_char_type, i_traits>& std::eek:perator << (
    std::basic_ostream<i_char_type, i_traits> & i_ostream,
    const Node & i_value
    );

    public:
    Node(void);
    Node(const std::string id);
    ~Node(void);

    const std::string & getId() const;
    void setId(const std::string &);
    private:
    std::string id;
    };
    }

    namespace std {

    template<
    typename i_char_type,
    class i_traits
    >

    basic_ostream<i_char_type, i_traits>& operator << (
    basic_ostream<i_char_type, i_traits> & i_ostream,
    const graph::Node & i_value
    ) {
    i_ostream << i_value.getId();
    return i_ostream;
    }


    } // end namespace


    //#endif

    //Node.cpp
    //#include "Node.h"

    using graph::Node;

    namespace graph {
    Node::Node(void)
    {
    }


    Node::Node(const std::string id) :id(id) {
    }

    Node::~Node(void)
    {
    }

    const std::string & Node::getId() const {
    return id;
    }

    void Node::setId(const std::string &id) {
    this->id = id;
    }
    }

    //Program.cpp
    //#include "Node.h"

    using graph::Node;
    using std::cout;
    using std::endl;

    int main() {
    Node a("a");
    Node b("b");

    cout << a << " and " << b << endl;
    }
    Gianni Mariani, Apr 14, 2007
    #4
  5. jakester

    James Kanze Guest

    On Apr 14, 11:14 pm, "twomers" <> wrote:

    [...]
    > namespace graph {


    [...]
    > ostream &operator<<(ostream &output, Node &node) {


    If this declaration compiles, it's time to change compilers,
    fast. It's not, and never has been, legal C++; a member
    operator<< takes only one (explicit) parameter.

    > output << node.getId();
    > return output;
    > }


    > }


    --
    James Kanze (Gabi Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Apr 15, 2007
    #5
  6. jakester

    James Kanze Guest

    On Apr 14, 11:50 pm, Gianni Mariani <> wrote:
    > jakester wrote:
    > > I am using Visual C++ 2007 to build the code below. I keep getting
    > > linkage error. Could someone please tell me what I am doing wrong? The
    > > code works until I start using namespace for my objects.


    [...]
    > > using std::eek:stream;
    > > using std::string;


    > notice, this is outside the graph: - In this case I suggest
    > you don't do this using in a header.


    I agree that I don't like using declarations at global scope,
    especially in a header. But I don't think that it has any
    relationship with his problem.

    > > namespace graph {
    > > class Node
    > > {
    > > friend ostream &operator<<(ostream &, Node &);


    > OK - friend in this case injects a declaration into the enclosing
    > namespace, i.e. graph. But, this probably doesn't do what you think you
    > want it to do since operator<< is a template not a straight function.


    His operator<< is not a template. On the other hand, he *has*
    effectively declared a function graph::eek:perator<<. When
    overload resolution choses this function, it will look for an
    implementation in the namespace graph.

    [...]
    > This is being defined in the global namespace.


    > > ostream &operator<<(ostream &output, Node &node) {
    > > output << node.getId();
    > > return output;
    > > }


    Which means that it is a different function. And that he still
    doesn't have a definition for the friend function in namespace
    graph which he declared in the header.

    > > //Program.cpp
    > > #include "Node.h"


    > > using graph::Node;
    > > using std::cout;
    > > using std::endl;


    > > int main() {
    > > Node a("a");
    > > Node b("b");


    > > cout << a << " and " << b << endl;
    > > }


    > when I compile your code on gcc I get this :


    > friendop1.cpp: In function 'int main()':
    > friendop1.cpp:69: error: ambiguous overload for 'operator<<' in
    > 'std::cout << a'
    > friendop1.cpp:53: note: candidates are: std::eek:stream&
    > operator<<(std::eek:stream&, graph::Node&)
    > friendop1.cpp:11: note: std::eek:stream&
    > graph::eek:perator<<(std::eek:stream&, graph::Node&)


    > Which is more like what I expect but I don't think that's totally right
    > either - not sure but it is irrelevant.


    Are you sure you compiled the same code? There was no
    "::eek:perator<<( std::eek:stream&, graph::Node& )" (the first
    candidate g++ mentions above) visible in Program.cpp.

    If you put all of the code in a single file, I'm not 100% sure,
    but I think g++ would be right. Normal name lookup finds the
    global function, and ADL finds the function in the namespace, so
    both are in the overload set (along with a lot of other
    functions from std, which are eliminated because they can't be
    called with the given arguments). In his example, he had two
    source files; graph::eek:perator<< was the only version visible in
    the header.

    Note that the name of the friend function graph::eek:perator<<
    isn't actually directly visible in namespace graph; friend name
    injection was removed by the standards committee. But the
    function will be found by ADL. If that's the only function that
    the compiler sees (case in the original code), then that's what
    overload resolution will choose, and since he's not implemented
    it, he gets the error message he saw. If there is also another
    function, with the exact same paramters, then the call is
    ambiguous.

    > The code at the end of this posting shows somthing that does compile and
    > run on gcc (probably will also on VC).


    > Some people will object to adding things to the std namespace some
    > people will say that this is specifically allowed.


    It depends on what you add.

    > I've seen some
    > compilers that won't work too well if it's not in the std:: namespace so
    > that's why I put it there but it may have been a buggy compiler.


    > --------------------------------------------------------------
    > #include <iostream>
    > #include <string>


    > namespace graph {
    > class Node;
    > }


    > namespace std {
    >
    > template<
    > typename i_char_type,
    > class i_traits
    > >

    > basic_ostream<i_char_type, i_traits>& operator << (
    > basic_ostream<i_char_type, i_traits> & i_ostream,
    > const graph::Node & i_value
    > );


    That's illegal, I think. About the only thing your allowed to
    add are specializations of existing templates, not new
    templates. But why be complicated? If he defines operator<< in
    the namespace graph, in his .cpp, everything should be just
    fine.

    --
    --
    James Kanze (Gabi Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Apr 15, 2007
    #6
  7. jakester

    James Kanze Guest

    On Apr 14, 11:34 pm, "jakester" <> wrote:
    > Could you help to explain what happens by declaring the operator<<
    > inside public as opposed to outside?


    First, ignore my previous response to twomers posting; I misread
    namespace for class. (It's late here.)

    > I am using C++, How to Program by
    > Deitel/Deitel (3rd edition) as a reference. On page 528, they talk
    > about implementation of operator overloading as member versus non-
    > member functions. This is their guidance:


    > 1. (), [], ->, or any assignment operator must be implemented as
    > member function
    > 2. when an operator function is implemented as a member function, the
    > leftmost operand must be a class object of the operator's class ... if
    > the left operand must be an object of a different class or built-in
    > type, this operator function must be implemented as a non-member
    > function.


    > They specifically state that << and >> operators should be
    > implemented as non-member functions. Doesn't this mean
    > outside public (as I had in the original post)?


    Non-member means that they are not members of the class. (A
    friend declaration does not declare a member of the class.)
    They still have to be defined in the correct namespace. Two
    functions with the same names in different namespaces are
    different functions.

    --
    James Kanze (Gabi Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Apr 15, 2007
    #7
  8. James Kanze wrote:

    ....
    >
    >> I've seen some
    >> compilers that won't work too well if it's not in the std:: namespace so
    >> that's why I put it there but it may have been a buggy compiler.

    >
    >> --------------------------------------------------------------
    >> #include <iostream>
    >> #include <string>

    >
    >> namespace graph {
    >> class Node;
    >> }

    >
    >> namespace std {
    >>
    >> template<
    >> typename i_char_type,
    >> class i_traits
    >> >

    >> basic_ostream<i_char_type, i_traits>& operator << (
    >> basic_ostream<i_char_type, i_traits> & i_ostream,
    >> const graph::Node & i_value
    >> );

    >
    > That's illegal, I think.


    In my recollection I see 50/50 with responses on that one with no one
    truly convinced that it is legal or illegal. Since you can't
    "specialize" a function (like you can a class), however, specialization
    is accomplished by overlaoding a function. For all intents and
    purposes, overloading is specialization for functions. So, was/is it
    the intent of the standard to not allow overloading ? I don't believe
    I've come across a definitive answer.

    > ... About the only thing your allowed to
    > add are specializations of existing templates, not new
    > templates. But why be complicated? If he defines operator<< in
    > the namespace graph, in his .cpp, everything should be just
    > fine.


    You're probably right. I remember having problems overloading
    operator<< in different namespaces in the past and what I did above
    solved the problem. I more than likely was a buggy compiler that didn't
    handle argument dependent lookup and the work-around is no longer needed.
    Gianni Mariani, Apr 15, 2007
    #8
  9. jakester

    James Kanze Guest

    On Apr 15, 3:26 am, Gianni Mariani <> wrote:
    > James Kanze wrote:


    > ...


    > >> I've seen some
    > >> compilers that won't work too well if it's not in the std:: namespace so
    > >> that's why I put it there but it may have been a buggy compiler.


    > >> --------------------------------------------------------------
    > >> #include <iostream>
    > >> #include <string>


    > >> namespace graph {
    > >> class Node;
    > >> }


    > >> namespace std {


    > >> template<
    > >> typename i_char_type,
    > >> class i_traits


    > >> basic_ostream<i_char_type, i_traits>& operator << (
    > >> basic_ostream<i_char_type, i_traits> & i_ostream,
    > >> const graph::Node & i_value
    > >> );


    > > That's illegal, I think.


    > In my recollection I see 50/50 with responses on that one with no one
    > truly convinced that it is legal or illegal.


    The standard says it's illegal; there's no doubt about that. In
    practice, however, I think the probability of it causing
    problems is about 0.

    > Since you can't "specialize" a function (like you can a
    > class), however, specialization is accomplished by overlaoding
    > a function.


    The standard is clear: a program may add template
    specializations to namespace std. Nothing about overloads.
    Specialization and overloading are two very different things.

    > For all intents and
    > purposes, overloading is specialization for functions.


    >From where do you get that? For some very specific purposes,

    specialization and overloading play similar rules. But in
    general, they are two very different mechanisms, with different
    rules accross the board.

    > So, was/is it
    > the intent of the standard to not allow overloading ? I don't believe
    > I've come across a definitive answer.


    I'd say that the actual words in the standar are a definitive
    answer. If you don't think that that they express the actual
    intent, a defect report would be in order; to date, there isn't
    one concerning this point, which means that it seems clear, and
    means what it seems to mean.

    > > ... About the only thing your allowed to
    > > add are specializations of existing templates, not new
    > > templates. But why be complicated? If he defines operator<< in
    > > the namespace graph, in his .cpp, everything should be just
    > > fine.


    > You're probably right. I remember having problems overloading
    > operator<< in different namespaces in the past and what I did above
    > solved the problem.


    And I confused namespace and class in my first reading of his
    problem. One gets an idea in one's head, and one doesn't see
    what is actually written. I think it's human nature; at least,
    I've never met anyone who was immune to it.

    --
    James Kanze (Gabi Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Apr 15, 2007
    #9
  10. James Kanze wrote:
    > On Apr 15, 3:26 am, Gianni Mariani <> wrote:

    ....
    >> For all intents and
    >> purposes, overloading is specialization for functions.

    >
    >>From where do you get that?

    I'm saying (or intending on saying) what you're ...

    .... For some very specific purposes,
    > specialization and overloading play similar rules.

    .... saying here.

    .... But in
    > general, they are two very different mechanisms, with different
    > rules accross the board.

    Yes. That's the point.



    >
    >> So, was/is it
    >> the intent of the standard to not allow overloading ? I don't believe
    >> I've come across a definitive answer.

    >
    > I'd say that the actual words in the standar are a definitive
    > answer. If you don't think that that they express the actual
    > intent, a defect report would be in order; to date, there isn't
    > one concerning this point, which means that it seems clear, and
    > means what it seems to mean.


    Ok - it probably needs to be expressed as a defect report because of the
    confusion. I also don't see there ever being a problem to overload into
    the std:: namespace as a way of extending support for user types.
    Gianni Mariani, Apr 15, 2007
    #10
  11. jakester

    jakester Guest

    On Apr 14, 8:05 pm, "James Kanze" <> wrote:
    > On Apr 14, 11:14 pm, "twomers" <> wrote:
    >
    > [...]
    >
    > > namespace graph {

    >
    > [...]
    >
    > > ostream &operator<<(ostream &output, Node &node) {

    >
    > If this declaration compiles, it's time to change compilers,
    > fast. It's not, and never has been, legal C++; a member
    > operator<< takes only one (explicit) parameter.
    >
    > > output << node.getId();
    > > return output;
    > > }
    > > }

    >
    > --
    > James Kanze (Gabi Software) email:
    > Conseils en informatique orientée objet/
    > Beratung in objektorientierter Datenverarbeitung
    > 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


    In my reference book, they say something similar to what you are
    saying too (overloading operators as member function should not have 2
    operands). I am quite confused. But the code does compile with VC++
    and g++. This observation adds much to my confusion.
    jakester, Apr 16, 2007
    #11
  12. jakester

    James Kanze Guest

    jakester wrote:
    > On Apr 14, 8:05 pm, "James Kanze" <> wrote:
    > > On Apr 14, 11:14 pm, "twomers" <> wrote:


    > > [...]


    > > > namespace graph {


    This is what I misread.

    > > [...]


    > > > ostream &operator<<(ostream &output, Node &node) {


    > > If this declaration compiles, it's time to change compilers,
    > > fast. It's not, and never has been, legal C++; a member
    > > operator<< takes only one (explicit) parameter.


    > > > output << node.getId();
    > > > return output;
    > > > }
    > > > }


    > In my reference book, they say something similar to what you are
    > saying too (overloading operators as member function should not have 2
    > operands). I am quite confused. But the code does compile with VC++
    > and g++. This observation adds much to my confusion.


    The problem is simply that I misread the code, and took a
    namespace for a class. Overloaded binary operators take one
    operand if a member, two if a free function. In namespace
    scope, they are free functions, so two operands are in order.

    I'm afraid my posting just added to the confusion. Namespaces
    and classes have nothing to do with one another.

    With regards to your original code: a friend declaration does
    *not* declare a member, but rather a function in the enclosing
    namespace. Which means, of course, that you have to define the
    function in the enclosing namespace; otherwise, you're defining
    some other function.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Apr 16, 2007
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Smith
    Replies:
    2
    Views:
    415
    Ivan Vecerina
    Oct 6, 2004
  2. Replies:
    1
    Views:
    389
  3. Replies:
    11
    Views:
    721
    James Kanze
    May 16, 2007
  4. hurcan solter
    Replies:
    3
    Views:
    715
    Cholo Lennon
    Aug 29, 2007
  5. Replies:
    1
    Views:
    581
    Michael DOUBEZ
    Sep 12, 2008
Loading...

Share This Page