PURE VIRTUAL FN

Pages: 12
Is below code the right way to overload a pure virtual function? Can overload be only done if I am able to override it?

1
2
3
4
5
6
7
8
9
struct I {
  virtual void func3();
  virtual void func4() = 0;
};

struct J : I {
  virtual void func3() = 0; 
  virtual void func4() = 0; 
};
code is nonsense, as is the question.
Last edited on
My understanding is below correct is right. please clarify if i am wrong.

1
2
3
4
5
6
7
8
9
struct I {
  virtual void func3();
  virtual void func4() = 0;
};

struct J : I {
  virtual void func3(); 
  
};
1
2
3
4
5
6
7
8
9
struct I {
	virtual void func4() = 0;
};

struct J : public I {
	 void func4() override {
		 // Code goes here
	 }
};

please clarify if i am wrong.

You are wrong. Your base class has a pure virtual function, func4(). This must be implemented in a class that derives from the base class. Nowhere does your derived class have an implementation of func4().
1
2
3
4
5
6
7
8
9
struct I {
  virtual void func3();
  virtual void func4() = 0;
};

struct J : I {
  virtual void func3() = 0; 
  virtual void func4() = 0; 
};

First post: Makes no sense <edit: This is too harsh. It actually can be valid, but perhaps a confusing design>; func3 is not pure virtual in base class, but is pure virtual in derived class. Of course, you could still make it legal by making the necessary implementations, but it would be very confusing for the end user:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
struct I {
  virtual void func3();
  virtual void func4() = 0;
};

void I::func3() { }

struct J : public I {
  virtual void func3() = 0; 
  virtual void func4() = 0; 
};

struct K : public J
{
    void func3() override;
    void func4() override;
};

void K::func3() { }
void K::func4() { }

int main()
{
    K k;
}


1
2
3
4
5
6
7
8
9
struct I {
  virtual void func3();
  virtual void func4() = 0;
};

struct J : I {
  virtual void func3(); 
  
};

Second post: Isn't necessarily wrong, but is incomplete to the point where nothing useful can be said about the class. (Theoretically, there could be other code that derives from J that is responsible for implementing func4, making both I and J be "abstract" classes.)

Is below code the right way to overload a pure virtual function? Can overload be only done if I am able to override it?
You are not using the word "overload" correctly. Overloading is when you have two functions with the same name, but one has different parameter types. (It gets more complicated when you overload between base and derived classes; by default, overload resolution won't look at the base class.)

If you have the same function (with the same signature) in both the base and derived class, but it isn't virtual, then you are shadowing the base-class function in the derived class.
Last edited on
Ok, so do you mean to say that pure virtual function can be overridden but not overloaded?
"Overloaded" is not an action that is applied to a function, it's simply a description of two or more functions. Overloading and overriding are two separate concepts that are independent of each other.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Example program
#include <iostream>
#include <string>

using std::string;

struct Base {
    virtual int twice(int number) = 0;

    string twice(string text)
    {
        return text + text;   
    }   
};

struct Derived : public Base
{
    using Base::twice; // enable overload resolution between base and derived
    int twice(int number) override
    {
        return 2 * number;
    }
};

int main()
{
    Derived der;
    std::cout << der.twice(21) << '\n';
    std::cout << der.twice("hello") << '\n';
}

42
hellohello

(In this example, 'twice' is overloaded to deal with both ints and strings. The int overload happens to be a pure virtual function that is overridden in the derived class.)
Last edited on
Ok, so pure virtual functions should not override non-pure virtual functions?
"Should not" --> I would say, correct, they generally should not. But it's not really a rule, so I don't want to say strongly here that you shouldn't ever do it. It would just be a weird design, but maybe has its place somewhere.

Essentially, you're making the base class non-abstract, but the derived class is forced to be abstract.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// Example program
#include <iostream>

using std::string;

struct Base {
    virtual void foo()
    {
        std::cout << "Base::foo\n";
    }
};

struct Child : public Base
{
    virtual void foo() override = 0;
};

struct Grandchild : public Child
{
    virtual void foo() override
    {
        std::cout << "Grandchild::foo\n";
    }
};

int main()
{
    Base base;
    base.foo();
    
    //Child child;
    //child.foo(); // error
    
    Grandchild grandchild;
    grandchild.foo();

    {
        Base* p_grandchild = &grandchild;
        p_grandchild->foo();
    }
    {
        Child* p_grandchild = &grandchild;
        p_grandchild->foo();
    }
}
Last edited on
My understanding is that a virtual function shall only be overridden by a pure virtual function if it is itself declared as pure virtual. Hence a pure virtual function must be overridden and overloaded.
No.

It was already explained that "overloading" is completely unrelated thing; nothing to do with virtual or pure (although you can overload them too).
1
2
3
// two functions with name "twice". Overload
int    twice(int);
string twice(string);



When class has virtual member function, classes derived from it can provide different behaviour, different implementation for the function.

When class has pure virtual member function, it is abstract. It cannot be used directly. You have to derive from it and provide non-pure implementation in the deriving class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Base {
    virtual void foo() = 0;
};

struct Child : public Base
{
};

struct Grandchild : public Child
{
    virtual void foo() override
    {
        std::cout << "Grandchild::foo\n";
    }
};

The Child inherits Base. Child IS-A Base. Child has function void foo(), but it is pure virtual.
Base is abstract. Child is abstract.
The Grandchild is a concrete class, because it overrides void foo() with something concrete.


1
2
3
4
5
6
7
8
struct First {
    virtual void bar() = 0;
};

struct Second : public First
{
    virtual void bar() override = 0;
};

Does Second have different bar() than First? Different behaviour?
Last edited on
What I meant to say is that a virtual function shall only be overridden by a pure virtual function if it is itself declared as pure virtual. Hence a pure virtual function must be overridden, as you can see from your code here. In your code case, a pure virtual function overrides a virtual function, hence no issues seen in your code. Pure virtual functions can also be overloaded by regular virtual functions or non-virtual functions. Pure virtual functions need to be implemented in derived classes for instantiation. So in short pure virtual function is a function that must be overridden and overloaded right?

So my below code

1
2
3
4
5
6
7
8
9
10
11
struct I {
  virtual void func3();
  virtual void func4() = 0;
  virtual void func4(double x, double y) = 0;
};

struct J : I {
  virtual void func3() override = 0;  //not acceptable as it overrides non pure virtual
  virtual void func4() override = 0; //acceptable as it overrides pure virtual
  virtual void func4(double x, double y); //overloading pure virtual. can this be done?
};
Last edited on
virtual void func4(double x, double y); //overloading pure virtual. can this be done?

Again, this is not overloading. This is overriding.

And yes, this MUST be done at some level. Without a definition of func4(double, double), all classes derived from class I would be abstract. It is not legal to instantiate an object of an abstract class.

Edit: Well, it is overloading also because func4 has 2 signatures in both I and J, but the important part of the answer is that this overrides I:func4(double, double).

Last edited on
Ok. So in short pure virtual function is a function that MUST be overridden and overloaded right?
If a base class function is defined as pure virtual, then the derived class(s) needs to provide a definition of the function if the derived class(s) is to be instantiated.

No class with a pure virtual function can be instantiated.
There is no "must overload".

I did ask:
1
2
3
4
5
6
7
8
struct First {
    virtual void bar() = 0;
};

struct Second : public First
{
    virtual void bar() override = 0;
};

Does Second have different bar() than First? Different behaviour?

Can First::bar() and Second::bar() behave differently?
If they don't, then why should Second have that member declaration at all?


You wrote:
1
2
3
4
5
6
7
struct I {
  virtual void func4(double x, double y) = 0;
};

struct J : I {
  virtual void func4(double x, double y); // can this be done?
};

That is the usual override. Can and is done. Your other examples are unorthodox, esoteric, (but not illegal).
Last edited on
I dont think First::bar() and Second::bar() behaves differently here. What I am trying to figure out is that if its really necessary that a pure virtual function MUST be overridden?
> if its really necessary that a pure virtual function MUST be overridden?

No, it is not necessary.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
struct A
{
    virtual void foo( int ) = 0 ; // pure virtual
    int a = 0 ;
};

struct B : A
{
    // B does not override and implement the pure virtual function
    // B is an abstract class; objects of type B can't be instantiated
    //                         except as sub-objects of a further derived class
    int b = 5 ;
};

struct C : B
{
    // C overrides and implements the virtual function
    virtual void foo( int ) override { /* ... */ }
    // objects of type C can be instantiated as the most derived class
};

struct D : C
{
    // D overrides and declares the function as a pure virtual
    virtual void foo( int ) override = 0 ;
    // D is an abstract class; objects of type D can't be instantiated
    //                         except as sub-objects of a further derived class
};
denver2020 wrote:
I dont think First::bar() and Second::bar() behaves differently here.

And we could not prove it with what we saw: neither First nor Second type objects can be instantiated, so we can't call either of those functions.

Lets create a a third class that derives and is not abstract (and add some more flesh on the bones):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Example program
#include <iostream>

struct Base {
    virtual void foo() = 0;
};

struct Child : public Base
{
    virtual void foo() override = 0;
};

struct Grandchild : public Child
{
    virtual void foo() override
    {
        Base::foo();
        Child::foo();
    }
};

int main()
{
    Grandchild grandchild;
    Base& base = grandchild;
    base.foo();
}

void Base::foo()
{
  std::cout << "Hello ";
}

void Child::foo()
{
  std::cout << "Dolly!\n";
}

Pages: 12