-2
#include <iostream>

class Base {
private:
    std::string hello{ "hello world!" };

public:
    Base()             = default;
    virtual ~Base()    = default;

    const std::string &getHello() const {
        return hello;
    }

    void setHello(const std::string &hello) {
        Base::hello = hello;
    }
};

class Derived : public Base {
public:
    Derived()                = default;
    ~Derived() override      = default;
};

int main(int argc, const char *argv[]) {
    Derived d;
    std::cout << d.getHello() << std::endl;
}

Base and Derived all use the default constructor and destructor, I explicitly declare them and marked as default. But in fact, if you don't explicitly declare them, the code can still work very well.

My confusion is whether I need to explicitly declare them. I heard two different arguments, some people think that whether or not you use them, you should declare them, others consider that if you need one, you declare it, otherwise you don't.

So what is the good practice?

0x11901
  • 339
  • 1
  • 14
  • 1
    Read more about this in a good [C++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). Most will tell you what Ctors/dtors the compiler writes implicitly and when it does / does not do so. – Carl Jun 26 '18 at 20:00
  • Although [this related Q&A](https://stackoverflow.com/q/4172722/335858) does not answer your question directly, it should give you enough understanding to figure out the answer for yourself. – Sergey Kalinichenko Jun 26 '18 at 20:03
  • This only "works very well" because you never do anything with any of the class members except the string. –  Jun 26 '18 at 20:08
  • You might be coming from a Java background? Your declaration of `class Base::z` defines a type, but that type isn't used anywhere. In particular, objects of type `Base` do not have subobjects of type `Base::z`. – MSalters Jun 26 '18 at 22:39
  • At your next job interview, which you would rather do: A) explain why your code does not need them (in this instance), with sufficient information to convince the hiring manager you know at least this much) or B) demonstrate your coding achievements and skill / experience by writing properly defined and implemented ctors / dtors ( including the rules (of three or five or zero) ). – 2785528 Jun 26 '18 at 22:58
  • @MSalters I actually want to say is that I use in-class initialization, so I don't need a custom constructor to initialize these member variable or type, and whether I use them or not isn't the key of this question. – 0x11901 Jun 27 '18 at 19:01

1 Answers1

2

The answer is (technically) no, you don't need to declare any of the special member functions explicitly - so long as you don't declare any other special member functions that result in suppressing other ones you might want (or need).

The rules regarding which special member functions are implicitly declared based on which ones you declare yourself are rather complex all things considered - this answer has a handy table to illustrate them. Unless you'd like to learn this by heart, you probably want to just be explicit in all cases. And even if you do know the rules by heart, somebody else reading your code might not. Core Guideline C.21 gives some more examples and goes in depth about why you'd want to do so.

However, while the guideline only suggests to define or default the remaining special member functions if you define any of them, I would like to encourage you to always explicitly default/delete all of them. I have two reasons for this:

  1. It makes your intent obvious.

  2. It prevents any nasty surprises later down the line. If you don't declare special member functions explicitly and later find out that you need a custom copy constructor for instance, you then have to remember to declare move operations if you haven't already - otherwise all code using these operations will break and it might not be immediately obvious why.

Also, this is not directly related to your question, but when talking about special member functions it's always useful to remind people of the rules of three, five and zero.

So to summarize - you don't have to, but you likely should.

Pandatyr
  • 284
  • 2
  • 8
  • 1
    Disagree with the final line. What the programmer should be striving for is [the Rule of Zero](https://en.cppreference.com/w/cpp/language/rule_of_three) and not implementing any special operators.This usually results in some Rule of Three/Five compliant [RAII-wrapped](https://stackoverflow.com/questions/2321511/what-is-meant-by-resource-acquisition-is-initialization-raii) abstractions around resources, but try to keep these abstraction classes close to the resources they are abstracting. – user4581301 Jun 26 '18 at 21:03
  • Disagree with everything. If you define the constructors/destructor/assignment operator explicitly when they are not needed, the only realistic outcome is that you will define them wrong, resulting in code that is incredibly hard to debug. If the defaults do what you want (which they almost always will if you use RAII classes as members , such as the standard library container and stringss) use the defaults. –  Jun 26 '18 at 21:55
  • @NeilButterworth That's what I was referring to, I'll update my answer to make it more clear. – Pandatyr Jun 26 '18 at 22:18
  • @user4581301That's a good point, I updated my answer to link to the cppreference site instead. – Pandatyr Jun 26 '18 at 22:31
  • So you means explicitly declare special member functions is the good practice? – 0x11901 Jun 27 '18 at 19:15
  • @0x11901 I mean you should always explicitly default/delete, even if they would be generated by the compiler, and provide a custom implementation if necessary. – Pandatyr Jun 27 '18 at 20:41