7

As far as I know the main difference (and may be the unique one) between classes and structs in C++ is that classes have their members private by default and structs have theirs public by default.

However, and probably because I was a C-developer before, I still continue to declare structs to hold only "public" fields, and I almost never declare methods (except constructors to initialize members).

I also want to take advantage of C++ inheritance for structs.

My questions are:

  1. Even if the language allows it, is it a good practice to inherits structs ?
  2. Is it possible to prevent a struct to declare a virtual method, which will create a vtable and modify the size of the struct ?

Thank you

M. Yousfi
  • 578
  • 5
  • 24
  • IMHO structs are just a C-compatibility feature and should not be used if not REALLY needed. – Trantor Sep 21 '17 at 08:17
  • public inheritance without a virtual destructor is a bad idea – Caleth Sep 21 '17 at 08:29
  • 2
    @Caleth Only sometimes. Other times paying the overhead for a virtual member is the bad idea. It all depends. – juanchopanza Sep 21 '17 at 08:30
  • @juanchopanza `struct A { ... }; struct B { A a; ... }` is much safer than `struct B : A { ... }`. I suggest *not inheriting* is better than *inheriting with nonvirtual destructor* – Caleth Sep 21 '17 at 08:32
  • 3
    @Caleth Sometimes. And sometimes you just need the inheritance. And no virtual destructor. – juanchopanza Sep 21 '17 at 08:33
  • @juanchopanza what do you think you *can't* do with composition that you *can* with inheritance, specifically excluding virtuals? – Caleth Sep 21 '17 at 08:35
  • 1
    There are really no "structs" in C++. You may ask whether it makes sense to inherit a class defined with the `struct` keyword, but that is a matter of opinion. – juanchopanza Sep 21 '17 at 08:36
  • 1
    @Caleth Template method pattern, CRTP, extending exception types, saving a lot of typing by using private inheritance, and situation where "is-a" relationships are required and we *don't* want dynamic allocation... – juanchopanza Sep 21 '17 at 08:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/154968/discussion-between-caleth-and-juanchopanza). – Caleth Sep 21 '17 at 08:41
  • 1
    @juanchopanza A nitpick: Extending (standard) exception types isn't really an example of inheritance excluding virtuals, because `std::exception::~exception` **is** virtual. – eerorika Sep 21 '17 at 08:55
  • 1
    The header `` contains hundreds of structs using inheritance and not a single virtual destructor in sight. – Bo Persson Sep 21 '17 at 11:59

6 Answers6

7

classes have their members private by default and structs have theirs public by default.

Structs also inherit public by default, where classes inherit private by default.

Even if the language allows it, is it a good practice to inherits structs ?

Sure. It works exactly as you would expect.

Is it possible to prevent a struct to declare a virtual method, which will create a vtable and modify the size of the struct ?

Not yet. There is a proposal for C++20+ (P0707) to allow exactly this, but it's still pretty young and not implemented far enough to be used anywhere. In particular, search for "3.6 plain_struct" to see how they enforce plain structs to be that.

In general I would recommend using a struct when you're using it as a "struct" sort of function - holding data without invariants. If you have invariants, you should keep them using encapsulation and data hiding, so it should be a class.

dascandy
  • 7,184
  • 1
  • 29
  • 50
  • 3
    Your last paragraph is clearly opinion-based and might suggests to a new user that `struct` are different from `class` in c++, which is not the case. – Holt Sep 21 '17 at 08:54
  • @Holt meaning-to-programmer is *more* important than meaning-to-compiler. compare `struct pair { T1 first; T2 second; ... }` to `class map { /* no public data members */ ... }` – Caleth Sep 21 '17 at 08:57
  • 1
    @Caleth But it's **your** opinion that `struct` means what you say it means. I am not saying that is not a good opinion, I am simply saying that this is not a general rule for all programmers out there, so it should not be present in a SO answer. – Holt Sep 21 '17 at 09:19
  • @Holt those examples are from `namespace std`. Advice on *good design* is on-topic on SO – Caleth Sep 21 '17 at 09:23
  • @Holt I recommend to the user that a `class` implies invariants exist, where a `struct` implies they do not exist. This is both a commonly-accepted communication style, and good advice to make your code clearer to others using the same communication method. There's no technical difference other than the default access specifier, as you correctly point out. – dascandy Sep 21 '17 at 12:07
4

Just want to address this question:

Even if the language allows it, is it a good practice to inherits structs ?

You should rid yourself of connotation that "struct" indicates POD. Sometimes, the most reusable components are those that don't encapsulate anything, despite having some behavior.

For instance, consider this meta-function:

template<typename T> struct is_foo :      std::false_type {};
template<>           struct is_foo<Foo> : std::true_type  {};

All of the above types (and the types behind the aliases for true and false) are declared with the struct keyword. This is simply because having everything public by default forwards the behavior we want without us having to spell it out every time.

Another time when you find yourself inheriting from a "struct" is when extending a C library. If the library defines a structure named struct Bar that is used to communicate with it, the easiest way you can add functionality to it, is by inheriting from Bar. Like this:

class ExtendedBar : Bar {
  void mem_func() {
    //Need to call the C library function? No problem
    c_library_func(this); // ExtendedBar is-a Bar
  }
};

The only important difference is the default accessibility levels. And the only thing you should concern yourself with (IMO) is which default accessibility works best for your purpose.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • I'd be really happy if template using could have specialisations. `template<> using is_foo = std::true_type;` – Caleth Sep 21 '17 at 09:39
2

Even if the language allows it, is it a good practice to inherits structs?

Yes it is. Just look around C++ STL (Standard Template Libraries). You will find struct in abundance.

Is it possible to prevent a struct to declare a virtual method, which will create a vtable and modify the size of the struct ?

No.... as of now.. As soon as you declare virtual functions.. the vtable will be created for struct

DevSolar
  • 67,862
  • 21
  • 134
  • 209
Daksh Gupta
  • 7,554
  • 2
  • 25
  • 36
2

Structs vs Classes

You are correct, a primary difference between struct and class in C++ is default access levels. Without an explicit access modifier, class members are private, and struct members public. Struct members can also be made private using an access modifier. Keep in mind; this also applies to inherited classes and structs.

As for a general recommendation: many use structs only for data and classes for everything with behavior [1]. In other words, structs for POD (Plain Old Data) types[2], this is a widespread practice. It does not mean you cannot have functionality related to accessing and setting data members, setting up constructors, destructors, etc. "If more functionality is required, a class is more appropriate. If in doubt, make it a class." Their guide also recommends structs instead of classes for functors and traits.

You have to keep in mind, aside from any technical upsides or downsides, there are other reasons to enforce specific practices and standards in a team, and on a project basis. As also mentioned in Google's style guide, we can add semantic meaning to the data structures we use. As a team member, I would want to know if structs have behavior or not. It would be nice to know, for instance, that all structs are just POD types.

The Joint Strike Fighter coding standard specifies, "A structure should be used to model an entity that does not require an invariant." While "A class should be used to model an entity that maintains an invariant." And that public and protected data should only be used in structs, not in classes. Their rationale for this is that a class can't control access to public members; hence, all data in a class should be private. Consider the needs of your project when deciding on coding standards.

Struct inheritance

When thinking about inheritance, you must consider what public inheritance means versus private inheritance. Keep in mind what access levels the new, derived one will have, and if it makes sense to inherit your structs. Struct members can be made private, if you inherit from this, the derived one will not have access to the base's private members.

struct base {   
    int public_data;

    private:
        int private_data;
};

struct derived : base { 
    derived() {
        public_data = 1;
        // private_data = 1;    // no access, won't compile
    }
};

In other words, inheritance might be considered more of a logical issue than an implementation one.

There is nothing, technically, fundamentally wrong with inheriting structs. It might be a benevolent practice, and it might, in some cases, be beneficial and make a lot of sense.

Keep in mind, in C++, structs can inherit from classes and vice versa.

See this question for more information on vtables: When is a vtable created in C++?

[1] https://google.github.io/styleguide/cppguide.html#Structs_vs._Classes

[2] http://en.cppreference.com/w/cpp/concept/PODType

sbrk
  • 378
  • 3
  • 10
1

As far as I know the main difference (and may be the unique one) between classes and structs in C++ is that classes have their members private by default and structs have theirs public by default.

The only difference between classes declared with the keyword struct, and those declared with the keyword class is indeed the default access specifier (which applies to bases too as well as members).

Indeed, the easiest way to understand structs is to understand that they are classes.

Even if the language allows it, is it a good practice to inherits structs ?

Sure. It is OK to inherit a class, and structs are classes.

Is it possible to prevent a struct to declare a virtual method, which will create a vtable and modify the size of the struct ?

No, there is no such feature as far as I know.

eerorika
  • 232,697
  • 12
  • 197
  • 326
-4

Given struct A { ... };, struct B { A a; ... } is much safer than struct B : A { ... }.

I suggest not inheriting is better than inheriting with non-virtual destructor. The only thing you lose is the implicit conversion from B*, B& to A*, A& etc. However you still have the explicit B b; b.a for those circumstances.

Caleth
  • 52,200
  • 2
  • 44
  • 75
  • 1
    You should explain your given. Also, this has nothing to do with the `struct` keyword specifically. – juanchopanza Sep 21 '17 at 08:41
  • `A` is whatever base type you want. This has a lot to do with inheritance sans all virtual methods. That it applies equally to class types defined using `struct` as to `class` doesn't impact it. – Caleth Sep 21 '17 at 08:44