2

In C++, if we have some virtual function within some base class(say Base), we'd like to override this virtual function, we will have to declare this virtual function again to make it work even compile in our derived classes.

class Base {
public:
    virtual void virtualFunction();
    static int s_whatSoEver[];
private:
    void _privateFunction();
}
class Derived {
public:
    virtual void virtualFunction();
}

Wasn't this stupid since if we'd like change the virtual function prototype, we'd have to change every declaration of the derived-s?

Also, why is it necessary to declare some protected or private function within the header file, since header file is used for public interface definition, and the user who makes use of this interface would never need to care about them at all? Maybe we can just directly implement & declare the private or protected function in the .cpp file just like Objective-C.

C++ doesn't have static initializer neither, what if we want to initialize some static class variable we'd have to make a class for this:

class BaseStaticVariableInitializer {
public:
    BaseStaticVariableInitializer() {
        Base::s_whatSoEver = new int[20];
        for (int i = 0; i < 20; i++) {
            s_whatSoEver[i] = xxx;
        }
    }
    ~BaseStaticVariableInitializer() {
         delete [] Base::s_whatSoEver;
    }
}

and initialize a static class constant for it specifically:

static BaseStaticVariableInitializer s_baseStaticVariableInitializer;

Sorry for my being ignorant, but what is your right way to write your c++ codes to fit well with DRY?

David
  • 3,843
  • 33
  • 36

4 Answers4

6

Wasn't this stupid since if we'd like change the virtual function prototype, we'd have to change every declaration of the derived-s?

No. If you are changing the virtual function prototype in the base class, you are changing a public interface. You shouldn't do that.

Also, why is it necessary to declare some protected or private function within the header file, since header file is used for public interface definition, and the user who makes use of this interface would never need to care about them at all?

protected members should be considered part of a class' public interface. The protected simply helps you from avoiding errors you would otherwise risk by having them public. But make no mistake: protected members are part of the class' interface, and should be treated as such.

Regarding privates in header files: Yes, I agree, it would in many ways be more logical to keep them in implementation files only. However, consider when you are passing a class by value:

foo(Bacon b)
{
    b.cook();
}

In order to call foo(), you need to have the full Bacon class definition available to the compiler. (Note: Only the class definition, not the definition of its member functions.) This is so the compiler can know how much stack space to allocate for the class when calling foo(). If the compiler had to search the implementation file as well to look for private variables, the parsing would be more complex (and compilation would probably be even slower).

Update

Since you mentioned DRY, I have to point this out. The DRY principle states:

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

Declaring virtual functions in the relevant classes does not violate this principle. They are not the same function. In Base, you state that Base::foo is virtual. In Derived, you state that Derived::foo also is virtual. Base::foo and Derived::foo are two separate functions, but it just so happens that both can be called through a pointer or reference to a Base.

Lstor
  • 2,265
  • 17
  • 25
  • What about private functions? Do we need to declare them in the header file? – David Jul 23 '13 at 02:16
  • @Lstor now you've made my answer irrelevant. – Eli Algranti Jul 23 '13 at 02:22
  • 3
    +1. Another reason for the need to include private functions is the possibility of `friend` declarations. It's perfectly possible to have the implementation of a friend-function in a .cpp file that only includes the header. When that .cpp file is compiled, the compiler needs to be able to check the correctness of the function calls of private member functions. – jogojapan Jul 23 '13 at 02:22
  • @EliAlgranti Sorry :-) – Lstor Jul 23 '13 at 02:24
  • @jogojapan Excellent point. I was actually discussing that limitation with a friend not too long ago. – Lstor Jul 23 '13 at 02:25
  • @jogojapan friend declaration seems to be a good reason to keep the private function declaration in the header file though it's feasible not to. – David Jul 23 '13 at 02:31
  • 1
    @david.wan I don't see how...? If you have a private function in a class defined in `A.h`, and that class has a friend function that is implemented in `B.cpp`, and `B.cpp` has a `#include "A.h"` and calls the private member, how could the compiler deal with this if the private member wasn't declared in `A.h`? – jogojapan Jul 23 '13 at 02:34
  • 2
    In addition to friends, inline functions also need to know the whole class definition. – syam Jul 23 '13 at 02:51
  • 1
    @jogojapan In this case, we must keep the private function declared in "A.h". Sorry for my confusion by the fact that it's feasible to keep the function declaration & definition within the implementation file for Objective-c. Obviously, there is no such things as "friend" in Objective-C. – David Jul 23 '13 at 03:05
  • @david.wan Things that make sense in one programming language often do not in another. While comparing language features and problem solving approaches might be useful in many cases, keep in mind that they are made for different domains and contexts. – Lstor Jul 23 '13 at 03:14
5

Wasn't this stupid since if we'd like change the virtual function prototype, we'd have to change every declaration of the derived-s?

That is exactly the point. If the signature changes in the base, you want the compiler to tell you, rather than potentially attempting to call the function with the wrong types. C++ is a statically typed, compiled language. The types are defined at compile time, if the type of the virtual function changes, you want to recompile to adapt to the change.

why is it necessary to declare some protected or private function within the header file, since header file is used for public interface definition, and the user who makes use of this interface would never need to care about them at all?

This is again a design choice in exactly the same way. In C++ the One Definition Rule requires that each type is defined exactly the same in all translation units (different compiled files). As mentioned before, C++ is a compiled language and in general the members affect the class, regardless of the access specifier (which is dropped during the compilation process). When the compiler creates an object of your type, it must allocate enough space for each and all data members, be them public, private or protected. When it builds a virtual table it needs to know how many slots need to be allocated for all the functions. Arguably, non-virtual functions don't affect the generated object/RTTI, but they potentially could.

If a new virtual function was added in a base class with exactly the same signature as the protected/private member function in a derived class, the latter becomes an override of the former and a new slot needs to be created in the virtual table. While this is probably unlikely, if the functions were hidden in a single translation unit (to which you might or not have access) you could potentially run into these issues.

C++ doesn't have static initializer neither, what if we want to initialize some static class variable we'd have to make a class for this

C++ doesn't have a static initializer, but I would surely not create a class for it. Static member variables need to be defined in a single translation unit, and in that translation unit they can be initialized. In simple cases you can do regular initialization directly, for more complicated cases you can create a function that will provide the initialized value.

int *Base::member = new int[10](); // value initialized (set to 0)

// abusing lambdas not to write a function:
int *Base::member2 = []()->int* { 
                         int *p = new int[10];
                         for (int i = 0; i < 10; ++i) p[i] = xxx;
                         return p; }();

Note that this does not control releasing of the resources (which you do in your code), but that could be readily handled with language constructs:

std::unique_ptr<int[]> Base::member(new int[10]());
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
1

Quick short answer . 1] for your 1st qustion see the diffrence between overriding & overloading in c++ 2] To initialize a static memebr , which can be done in static member function

class Base {
public:
  virtual void virtualFunction();
  static int s_whatSoEver[];

  static void BaseStaticVariableInitializer() {
    Base::s_whatSoEver = new int[20];
    for (int i = 0; i < 20; i++) {
        s_whatSoEver[i] = xxx;
    }
}
private:
 void _privateFunction();

define this seperately in .cpp file

 static int Base::s_whatSoEver[20];
Anand Rathi
  • 790
  • 4
  • 11
  • 2
    Thanks for pointing my misunderstanding for overloading & overriding & overwriting, I've corrected it out there. You've define s_whatSoEver there, but where is the place your initialize them? Besides, what if the static class variable is of some user defined class? – David Jul 23 '13 at 02:34
  • @david.wan you are welcome Dave, in C++ other than declaring , you have to define it . which has to be o=done in at the most one translation uniot.[.cpp file] You can initialize at the time of deining it if its Simple variable or has constructor. Else you can do it in static function like I have done in the answer – Anand Rathi Jul 23 '13 at 05:39
1

Why is it necessary to declare some protected or private function within the header file? ...

What is your right way to write your c++ codes to fit well with DRY?`

You can use Pimpl idiom to hide implementation details (declaration of private members and methods signatures) from header file. Additionally you will get faster build. Qt uses extensively this idiom.

Community
  • 1
  • 1
Leonid Volnitsky
  • 8,854
  • 5
  • 38
  • 53