Dog() = default;
is a user declared constructor (not to be confused with a user defined constructor). It is a defaulted default constructor. Typically you would use it when the class has other constructors but you still want the compiler to generate a default constructor (or rather a “defaulted default constructor”. This is C++ terminology at its best. Note how the two “default”s have slightly different meaning).
A user declared constructor prevents a class from being an aggregate. From cppreference, only for C++20:
An aggregate is one of the following types:
- array type
- class type (typically, struct or union), that has
- no private or protected direct non-static data members
- no user-declared or inherited constructors
- no virtual, private, or protected base classes
- no virtual member functions
As an example, consider:
#include <iostream>
#include <type_traits>
class Dog {
int x;
public:
Dog()=default;
};
class Horse {
int x;
};
class Swan {
public:
int x;
};
class Cow {
public:
int x;
Cow() = default;
};
int main() {
std::cout << std::is_aggregate_v<Dog>;
std::cout << std::is_aggregate_v<Horse>;
std::cout << std::is_aggregate_v<Swan>;
std::cout << std::is_aggregate_v<Cow>;
}
Output
0010
The first two, Dog
and Horse
, resemble your two versions of Dog
. They are not aggregates, because they have private members. Swan
is an aggregate, but Cow
is not, because it has a user declared constructor.
Something that works with aggregates, but not with non-aggregates, is designated initializers (same cppreference page):
Swan s{.x=3}; // OK
Cow c{.x=4}; // Error: Cow is not an aggregate
TL;DR: I am not aware of a difference between your two Dog
s, but in general the presence of a user declared constructor can make a difference.