views:

728

answers:

3

I have a class that uses a struct, and I want to overload the << operator for that struct, but only within the class:

typedef struct my_struct_t {
  int a;
  char c;
} my_struct;

class My_Class
{
  public:
    My_Class();
    friend ostream& operator<< (ostream& os, my_struct m);
}

I can only compile when I declare the operator<< overload w/ the friend keyword, but then the operator is overloaded everywhere in my code, not just in the class. How do I overload the << operator for my_struct ONLY within the class?

Edit: I will want to use the overloaded operator to print a my_struct which IS a member of My_Class

+10  A: 

Don't use operator <<. Use a named member function, and make it private.

class My_Class
{
  public:
    My_Class();
 private:
    void Print( ostream & os, const my_struct & m );
};

Note you should pass the structure as a const reference, whichever method you use.

Edit: There is no need to make the operator << a member of the class just so you can use it to print a member of the class. You can make it a friend of the struct, or a completely free function, which the class then uses.

anon
+1  A: 

If by "only overloaded in the My_Class" you mean only visible / usable by my class you could use a non-member overload that's only visible to My_Class. E.g.

   struct my_struct {
      int a;
      char c;
   };

   class My_Class
   {
      publiC:
         My_Class();
   }

Then in My_Class.cpp:

namespace {
    ostream& operator(ostream& os, const my_struct& mystruct ) {
         os << mystruct.a << mystruct.c;
    }
}
maccullt
anon
I meant to edit and somehow got a copy of the answer. So I deleted the first one. Then the question changed so I deleted my 2nd one and was going to add a third answer but SO suggested that I edit an existing one so I undeleted the first one and edited by which time it was a clone of yours :-(
maccullt
+8  A: 

How do I overload the << operator for my_struct ONLY within the class?

Define it as

static std::ostream & operator<<( std::ostream & o, const my_struct & s ) { //...

or

namespace {
    std::ostream & operator<<( std::ostream & o, const my_struct & s ) { //...
}

in the .cpp file in which you implement MyClass.

EDIT: If you really, really need to scope on the class and nothing else, then define it as a private static function in said class. It will only be in scope in that class and it's subclasses. It will hide all other custom operator<<'s defined for unrelated classes, though (again, only inside the class, and it's subclasses), unless they can be found with ADL, or are members of std::ostream already.

Assumes one .cpp file only contains one class, which is often not the case.
anon
That's the case for most of my classes. If there's a second class in the `.cpp` file, it's an implementation detail of the "main" class, and the extended exposure won't matter. And it helps keep the `.h` file clean, which should never be underestimated.
+1 I thought that the unnamed namespace would break ADL rules, but after testing with both g++ and comeau it seems as if it does not. Nice.
David Rodríguez - dribeas
The other issue, which the questioner does not make clear, is does he want to use any memebers of My_Class, during the output? If he does, the private member is the only real option.
anon
The anon namespace is equivalent to `namespace _unique {} using namespace _unique;`, so the function will be found, ADL or not.
@Neil: `my_struct` is distinct from `MyClass`, so why would `operator<<` for `my_struct` want to use private members of `MyClass`?
+1. I agree with Neil that this solution has the limitation that it "assumes one .cpp file only contains one class". However, C++ doesn't provide a particularly clean way to do what the question is asking. Personally I find that scoping definitions in a .cpp implementation file often works well enough, and is probably an underutilized technique. I think most people learning C and C++ come away with the impression that you should to put all namespace-scope definitions in a .h file, rather than striving for clean and minimally-defined interfaces.
Marsh Ray
@mmutz He wants to associate it with the class - there must be some reason for that. Perhaps MyClass contains some special formatting instructions - who knows?
anon