-
Notifications
You must be signed in to change notification settings - Fork 82
Classes and Structs
In SeqAn3 we ask that you pick one of the following threee "styles" for data-owning class types (depending on the requirements, pick the top-most one):
-
aggregate POD class types:
- satisfy both the PODType definition and support aggregate initialization
- no constructor/destructor definitions at all
- no virtual
- no private/protected (except statics and typedefs)
- no member initializers
- all data members same definition
- denoted by the
struct
keyword - data members should be prefixed with
_
to mark them as "private" - data members writable through aggregate initialization, assignment operator and/or setter functions
- data members readable through structured bindings and/or getter functions
- satisfy both the PODType definition and support aggregate initialization
-
non-aggregate POD class types:
- satisfy the PODType definition, but don't support aggregate initialization
- custom constructors and/or assignment operators
- BUT rule-of-six constructors/destructors/assignment-ops are default and explicitly defaulted
- no virtual
- no private/protected (except statics and typedefs)
- no member initializers
- all data members must be POD, too
- denoted by the
class
keyword - data members should be prefixed with
_
to mark them as "private" - data members writable through constructors, assignment operators and/or setter functions
- data members readable through getter functions
- satisfy the PODType definition, but don't support aggregate initialization
-
non POD class types:
- everything that needs non-default rule-of-six constructors/destructors/assignment-ops
- all rule-of-six constructors/destructors/assignment-ops should be specified (can explicitly default or delete)
- denoted by the
class
keyword - data members should usually be
protected
orprivate
(and are not prefixed with_
) - data members writable through constructors, assignment operators and/or setter functions
- data members readable through getter functions
- member functions should never be virtual, see Dynamic and Static Polymorphism for more details.
In addition there are constructs implemented as classes that don't "store data":
-
certain metafunctions:
- see Metafunctions
-
traits types:
- only contain other type declarations and
static const
/static constexpr
data members - used to specialize the behaviour of other non POD class types
- denoted by
struct
keyword and a_traits
suffix in the name
- only contain other type declarations and
Whenever you have something that is stored in a container and/or copied around frequently, it might profit from being a POD type vs a non-POD type, e.g. our alphabet concept requires alphabets to be POD types. If you implement a POD type, check whether you can also make it an aggregate type so that you can avoid boilerplate code and improve readability of the data structure, e.g. the dna4
alphabet is an aggregate POD type, but the compound_alphabet_u
is a non-aggregate POD type.
If you have a general purpose data structure that deals with more complex data, needs encapsulation and/or customized construction behaviour, opt for the most general of the above types.
Note that there are other types, as well (e.g. non-POD aggregate types), but that we explicitly require you choose one of the distinctions above.
struct aggr_pod_type
{
char _c;
char get_c() const
{
return _c;
}
void set_c(char const c)
{
_c = c;
}
};
class non_aggr_pod_type
{
// all public
public:
char _c;
// Rule-of-six explicitly defaulted/deleted, () may not be deleted
non_aggr_pod_type() = default;
constexpr non_aggr_pod_type(non_aggr_pod_type const &) = default;
constexpr non_aggr_pod_type(non_aggr_pod_type &&) = default;
constexpr non_aggr_pod_type & operator =(non_aggr_pod_type const &) = default;
constexpr non_aggr_pod_type & operator =(non_aggr_pod_type &&) = default;
constexpr ~non_aggr_pod_type() = default;
// user defined constructors
non_aggr_pod_type(char const c) :
_c{c}
{}
// silly example:
non_aggr_pod_type(std::string const & s) :
_c{s[0]}
{}
char get_c() const
{
return _c;
}
void set_c(char const c)
{
_c = c;
}
};
class non_aggr_non_pod_type
{
// always specify public, protected, private in this order
public:
// Rule-of-six all explicitly listed, some non-defaulted
non_aggr_pod_type() :
c{'a'}
{}
constexpr non_aggr_pod_type(non_aggr_pod_type const &) = default;
constexpr non_aggr_pod_type(non_aggr_pod_type &&) = default;
constexpr non_aggr_pod_type & operator =(non_aggr_pod_type const &) = default;
constexpr non_aggr_pod_type & operator =(non_aggr_pod_type &&) = default;
constexpr ~non_aggr_pod_type() = default;
// user defined constructors
non_aggr_pod_type(char const _c) :
c{_c}
{}
char get_c() const
{
return c;
}
void set_c(char const _c)
{
c = _c;
}
protected:
char c;
};