5

I'd appreciate if anyone could enlighten me what is going on here: Say I declare the following

class Base {
public:
    virtual void member(Base b) = 0;
};

which give the following compiler error:

pvf.cpp:3:18: error: cannot declare parameter ‘b’ to be of abstract type ‘Base’
     virtual void member(Base b) = 0;
              ^
pvf.cpp:1:7: note:   because the following virtual functions are pure within ‘Base’:
     class Base {
   ^
pvf.cpp:3:18: note:     virtual void Base::member(Base)
     virtual void member(Base b) = 0;

However, if I pass by reference, it compiles without problems:

class Base {
public:
    virtual void member(Base& b) = 0;
};

Furthermore, I'd like to implement member() in the derived class as

class Base {
public:
virtual void member(Base& b) = 0;
};

class Derived : public Base {
public:
    void member(Derived& d) {};
};

int main() {
    Derived d;
}

However, (obviously?) I get

pvf.cpp: In function ‘int main()’:
pvf.cpp:12:14: error: cannot declare variable ‘d’ to be of abstract type ‘Derived’
    Derived d;
    ^
pvf.cpp:6:8: note:   because the following virtual functions are pure within ‘Derived’:
    class Derived : public Base {
    ^
pvf.cpp:3:15: note:     virtual void Base::member(Base&)
    virtual void member(Base& b) = 0;
user32849
  • 609
  • 1
  • 6
  • 16
  • 1
    If you declare `member(Base b)` (without the reference), that means every time someone calls `member`, the parameter will be passed by value and copied (and if the object being passed is actually a `Derived`, it will get *sliced* during the copy). – Cameron Sep 22 '15 at 22:24
  • Yes. All as expected. Use `Base&`. What's your question? – Karoly Horvath Sep 22 '15 at 22:25

1 Answers1

4

Your first function

virtual void member(Base b) = 0;

takes a parameter of class Base by value which requires an instance of Base to be passed to it. But as Base is an abstract class (because it contains a pure virtual function) it cannot be instantiated and therefore you cannot create an instance of Base to pass to it! That is the reason for your first error.

In your second case, in your derived class you declare a function

void member(Derived& d) {};

which you may think overrides the base class virtual function

virtual void member(Base& b) = 0;

but it does not (it in fact, hides it - see Why does a virtual function get hidden? for an explanation of this), and so Derived remains abstract class because you have not provided an implementation of the pure virtual function in the base class. For this reason Derived also cannot be instantiated. Derived classes that fail to provide an implementation for a base class pure virtual function will remain abstract just like the base class.

Community
  • 1
  • 1
mathematician1975
  • 21,161
  • 6
  • 59
  • 101
  • Thanks! What I am trying to achieve is a base class that forces all its derived classes to implement a pass-by-value method Derived::member(Derived d). Am I approaching this all wrong? – user32849 Sep 22 '15 at 22:38
  • 1
    @user: We'd have to know more about your specific application to determine if this is "wrong" or not, but it's certainly possible using the curiously recurring template pattern (CRTP): `template class Base { public: virtual void member(TDerived b) = 0; }; class Derived : Base { ... };`. This is probably not what you really want, though... – Cameron Sep 22 '15 at 22:42
  • I am writing some statistical software, and I'd like to be able to do something like Distribution::sample(Parameters p) in the general code, but I'd like to be able to plug in the type of distribution at run-time, such as Gaussian::sample(NormalParam p) etc., where Gaussian derives from Distribution and NormalParam derives from Parameters, and I'd like to assert that all distributions implement ::sample(). An Observation class requires me to pass an object of the same class to a method. The passing-by-value is just a curiosity I stumbled upon, and not a requirement - always trying to learn ;-) – user32849 Sep 22 '15 at 22:51
  • 1
    Use references to bases. – Karoly Horvath Sep 22 '15 at 23:16
  • Could you elaborate on that a bit, please (sorry if you're saying something obvious - I'm a really a noob when it comes to C++...) – user32849 Sep 22 '15 at 23:39