Contrary to what younger developers, or people coming from C believe at first, a struct can have constructors, methods (even virtual ones), public, private and protected members, use inheritance, be templated… just like a class .
1 Answer. No, you cannot define a function inside the structure of C Programming, but you can do so in C++, rather you can have a function pointer in a “struct” in C Language.
Using a struct we can achieve all the functionality of a class : constructors (that can be modified/overloaded), destructors (that can be modified/overloaded), operator overloading, instance methods, static methods, public / private / protected fields/methods.
Only C++ has added an extra rule that allows to omit the struct (and class ) keyword if there is no ambiguity. If there is ambiguity, also C++ requires the struct keyword in some places. A notorious example is stat on POSIX systems where there is a struct stat and a function stat .
A struct
in C++ is actually a class
definition where its content are public
, unless specified otherwise by including a protected:
or private:
section.
When the compiler sees a class
or struct
, it first digests all the declarations within the block ({}
) before operating on them.
In the regular method case, the compiler hasn't yet seen the type declared.
C++ standard 3.4.1:
.4:
A name used in global scope, outside of any function, class or user-declared namespace, shall be declared before its use in global scope.
This is why global variables and functions cannot be used before an afore declaration.
.5:
A name used in a user-declared namespace outside of the definition of any function or class shall be declared before its use in that namespace or before its use in a namespace enclosing its namespace.
same thing just written again as the .4 paragraph explictely restricted its saying to "global", this paragraph now says "by the way, its true as well in namespeces folks..."
.7:
A name used in the definition of a class X outside of a member function body or nested class definition29 shall be declared in one of the following ways: — before its use in class X or be a member of a base class of X (10.2), or — if X is a nested class of class Y (9.7), before the definition of X in Y, or shall be a member of a base class of Y (this lookup applies in turn to Y ’s enclosing classes, starting with the innermost enclosing class),30 or — if X is a local class (9.8) or is a nested class of a local class, before the definition of class X in a block enclosing the definition of class X, or — if X is a member of namespace N, or is a nested class of a class that is a member of N, or is a local class or a nested class within a local class of a function that is a member of N, before the definition of class X in namespace N or in one of N ’s enclosing namespaces.
I think this speaks of all the code that does not stand in cpu executed code (eg declarative code).
and finally the interesting part:
3.3.7 Class scope [basic.scope.class]
1 The following rules describe the scope of names declared in classes.
1) The potential scope of a name declared in a class consists not only of the declarative region following the name’s point of declaration, but also of all function bodies, brace-or-equal-initializers of non-static data members, and default arguments in that class (including such things in nested classes).
2) A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.
3) If reordering member declarations in a class yields an alternate valid program under (1) and (2), the program is ill-formed, no diagnostic is required.
particularly, by the last point they use a negative manner to define that "any ordering is possible" because if re-ordering would change lookup then there is a problem. its a negative way of saying "you can reorder anything and its ok, it doesnt change anything".
effectively saying, in a class, the declaration is looked-up in a two-phase compilation fashion.
"why can I conduct a similar concept in a struct, but not get yelled at for it?"
In a struct
or class
definition you're presenting the public interface to a class and it's much easier to understand, search and maintain/update that API if it's presented in:
For predictable order, people have their own styles and there's a bit of "art" involved, but for example I use each access specifier at most once and always public
before protected
before private
, then within those I normally put typedef
s, const
data, constructors, destructors, mutating/non-const functions, const
functions, static
s, friend
s....
To minimise clutter, if a function is defined in the class, it might as well be without a prior declaration. Having both tends only to obfuscate the interface.
This is different from functions that aren't members of a class - where people who like top-down programming do use function declarations and hide the definitions later in the file - in that:
people who prefer a bottom-up programming style won't appreciate being forced to either have separate declarations in classes or abandon the oft-conflicting practice of grouping by access specifier
Classes are statistically more likely to have many very short functions, largely because they provide encapsulation and wrap a lot of trivial data member accesses or provide operator overloading, casting operators, implicit constructors and other convenience features that aren't relevant to non-OO, non-member functions. That makes a constant forced separation of declarations and definitions more painful for many classes (not so much in the public interfaces where definitions might be in a separate file, but definitely for e.g. classes in anonymous namespaces supporting the current translation unit).
Best practice is for classes not to cram in a wildly extensive interface... you generally want a functional core and then some discretionary convenience functions, after which it's worth considering what can be added as non-member functions. The std::string
is an often claimed to have too many member functions, though I personally think it's quite reasonable. Still, this also differs from a header file declaring a library interface, where exhaustive functionality can be expected to be crammed together making a separation of even inline
implementation more desirable.
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