I have a class with a member function with a lengthy return type:
/* MyClass.hpp */
namespace foo
{
class MyClass
{
public:
SomeNameSpace::Lengthy_return_type_name someFunction(params...);
};
}
I want to make this more readable without making things confusing for the reader, and I don't necessarily want to expose the typedef to the outside world. So in MyClass.hpp I added the following typedef within MyClass:
/* MyClass.hpp */
namespace foo
{
class MyClass
{
private:
typedef SomeNameSpace::Lengthy_return_type_name myType;
public:
myType someFunction(params...);
};
}
Now, in MyClass.cpp I have a dilemma because myType is not visible to be able to use as a return type. I could use MyClass::myType if I made the typedef public, but I don't like that since I think it is confusing and also exposes myType. I could also add the typedef to the top of MyClass.cpp, but this might take away from the meaning since readers would have to do a little digging to find out what the type is referring to.
Am I overthinking this? What is best practice in this case?
Usually, header files contain declarations, source files contain code. So, if in source file A.c you need a function implemented in source file B.c , you just include B.h to have its declaration.
typedef s are always "local to a file". So it is not exactly clear what you mean by "making it local to a file". Typedef does not introduce an entity with its own linkage, it simply creates an alias to an existing type.
C - typedef. The C programming language provides a keyword called typedef, which you can use to give a type a new name. Following is an example to define a term BYTE for one-byte numbers −. After this type definition, the identifier BYTE can be used as an abbreviation for the type unsigned char, for example..
Either you will have to take the typedef out of struct node declaration and move it to the header file, or you move the whole typedef + structure declaration to the header file. The former solution is generally what you want, since it allows you to have some information hiding. So, my suggestion is to write this in the header file:
In my view, a header file should have the minimum practical interface to a corresponding .c or .cpp. The interface can include #defines, class, typedef, struct definitions, function prototypes, and less preferred, extern definitions for global variables.
Last Updated : 29 Jul, 2021 The Content-Type header is used to indicate the media type of the resource. The media type is a string sent along with the file indicating the format of the file. For example, for image file its media type will be like image/png or image/jpg, etc.
The short answer is: Make the alias public. There is no reason to make it private.
For illustration I take your example one step further. Suppose myType
is not just an alias but a new type:
struct foo {
private:
struct myType {};
public:
myType someFunction();
};
Now lets see what this brings: Is myType
really private? No.
A caller can do
foo f;
auto x = f.someFunction();
using myMyType = decltype(x);
Tada, the user has an alias for myType
called myMyType
. The return type of a public function is not private! Only the name foo::myType
is private, but types being referd to by different names is common. There is no point in trying to hide that name. The only thing you achieve is to force the user to use a different name.
Also consider that one might expect the definition
foo::myType foo::someFunction() {}
to fail to compile, because foo::myType
is defined in the private section of foo
. Though, return types of public methods cannot be really private. If the above definition was not allowed you could write:
decltype( declval<foo>().someFunction() ) foo::someFunction() {}
So there would be really no point in disallowing the above definition.
Live example
Definitely overthinking, because your callers need to have full definition available anyway. No point in restricting access to something they have to know.
Besides, what's the point in hiding a typedef
from callers when it is used as a return type? It doesn't buy you anything, there's no encapsulation involved in this particular case.
Lastly, may I recommend switching to modern syntax for doing the same thing?
using myType = SomeNameSpace::Lengthy_return_type_name;
You will eventually come to love this, since it offers so much more than plain typedefs, e.g. alias templates.
That's a good idea to define all types at the beginning.
Just have a look at any class implementation of the Standard Library: vector by example. The "Member type section" is filled by useful typedefs.
If you look at the implementation details, the general scheme is:
template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
class vector : protected _Vector_base<_Tp, _Alloc>
{
typedef _Vector_base<_Tp, _Alloc> _Base;
typedef typename _Base::_Tp_alloc_type _Tp_alloc_type;
// ...
public:
typedef _Tp value_type;
typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;
typedef __gnu_cxx::__normal_iterator<const_pointer, vector> const_iterator;
// ...
public:
iterator begin();
const_iterator begin() const;
// ...
};
If the method is public you should declare the typedef to be public too. Just stay coherent and consistent.
As mentioned by others and since C++11, it is better to use using
instead of typedef
, see What is the difference between 'typedef' and 'using' in C++11?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With