Virtual function

Pages: 1234
@seeplus Ok.
Extending the C string constant's lifetime with the reference isn't a good idea

It looks like returning a reference variable disables named return value optimization, at least in practice:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <cstdio>
struct A 
{ 
  A() = default;
  A(A const&) { std::puts("copied\n"); } 
};

A f() { A const a; return a; }
A g() { A const& ra = A{}; return ra; }

int main()
{
    g();
}

To my understanding the "standard" explanation for this behavior depends on whether a names the referent or the reference.
https://eel.is/c++draft/class.copy.elision#1.1
I'm not certain about the standard's contents, but in practice there is no implementation divergence - C++20 compilers don't optimize g:
https://godbolt.org/z/d5xTn6qE5

Are there more reasons why regularly relying on lifetime extension isn't a good idea?
Last edited on
Are you trying to explain to me that acting this way I am creating a temporary (or anonymous) object which is just useless in this context?

In the paper which shared with me @George P, I read :
When this happens, a temporary object is created and initialized with the rvalue, and the reference to const is bound to that temporary object. A temporary object (also sometimes called an anonymous object) is an object that is created for temporary use (and then destroyed) within a single expression.
Last edited on
Geckoo the behavior of
const std::string &winner = "Simple output";
Is
1. Convert the string literal into a std::string
2. Create a temporary object to hold the resulting string (i.e. "materialize a temporary")
3. Bind the reference to the temporary object, whose lifetime is extended so that winner doesn't become a dangling reference.

On the other hand,
const std::string winner = "Simple output";
Only calls std::string's constructor. This is an example of copy-initialization.

Are you trying to explain to me that acting this way I am creating a temporary object which is just useless in this context?


Both options:
1
2
const std::string& winner = "Simple output";
const std::string winner = "Simple output";

Make only one std::string object.

Whether the object starts out temporary and then has its lifetime extended to match the reference's lifetime, or starts out as an object with automatic storage duration, doesn't make much difference in isolation.

It can make some difference to surrounding code, see my earlier post.
Maybe other folks can come up with more reasons why using references in this way might or might not be a good idea.
Last edited on
@mbozzi Thank you for your explanation. I made a mistake introducing this ref. Now I understand.

Another question : I noticed that an overriden function in a derived class can be private. Is there a good idea or not? It seems safe...

1
2
3
4
5
6
7
8
9
10
11
class player2 : public base {

public:
    player2() : base("Computer") {};
    ~player2() = default;

private:
    virtual void setChoice()override {
        m_choise = utilities::computerHand();
    }
};
Last edited on
Peter87 did answer that in https://cplusplus.com/forum/beginner/284974/2/#msg1236225


Herb Sutter did recommend somewhere non-virtual interface that makes use of (private) virtual implementation.
Herb Sutter did recommend somewhere non-virtual interface that makes use of (private) virtual implementation.


Here:
http://www.gotw.ca/publications/mill18.htm
Thanks for the relevant reply and the link ++

Prefer to make virtual functions private.

That's easy. This lets the derived classes override the function to customize the behavior as needed, without further exposing the virtual functions directly by making them callable by derived classes (as would be possible if the functions were just protected)... Only if derived classes need to invoke the base implementation of a virtual function, make the virtual function protected.
Hello. This thread is captivating. I have another question : in my previous code I use a pure virtual function in the base class. If I change it for a virtual function with a simple body, what will be changed in the runtime process? I read many different explanations on the web, but it is not always consistent... To be clear, what will be the difference between those alternatives (both they work fine in the previous code) ?

virtual void function() = 0; // pure virtual function

virtual void function() { std::cout << "simple body" << std::endl; }
Last edited on
A pure virtual class can't be instantiated.
A pure virtual class can't be instantiated.

Short. Clear. Thank you ++
I guess by "pure virtual class" seeplus mean what is normally known as an "abstract class".

An abstract class is a class that either declares a pure virtual function or that inherits a pure virtual function without overriding it. As seeplus said, you cannot create instances (objects) of an abstract class.

Quite often it doesn't make sense to create instances of the base class and there is no default implementation that makes sense. By making the function pure virtual you force derived classes to provide their own implementation of the function (unless they intend to be abstract classes).

Abstract classes also avoid the problem of object slicing. Another way to avoid the problem is to disable copy/move construction and copy/move assignment but this is not necessary with abstract classes.
https://en.wikipedia.org/wiki/Object_slicing
Last edited on
Thanks @Peter87. As I understand, an abstract class has at least one pure virtual function. In other words, a function that has no definition - only a declaration with 0. So the child must define the pure virtual function in their base class.
But I guess that "during the runtime" there is another behavior between a pure virtual class and a virtual class with a body. No? Is there an object for virtual function - when there is nothing for a pure virtual function?
> But I guess that "during the runtime" there is another behavior ...
> Is there an object for virtual function - when there is nothing for a pure virtual function?

An abstract class can be used only as a base class of some other class;
no objects of an abstract class can be created except as subobjects of a class derived from it
http://eel.is/c++draft/class.abstract#note-3


For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>

struct A { int v = 9 ; virtual ~A() = default ; } ;

struct B : A { virtual ~B() = 0 ; /* pure virtual destructor */  B() { std::cout << "B::constructor\n" ; } } ;

B::~B() { std::cout << "B::pure virtual destructor\n" ; }

struct C : B {} ;

int main()
{
   A a ; // fine; A is not an abstract class
   
   // B b ; // *** error *** B is an abstract class
   
   C c ; // fine; C is not an abstract class. need to construct a sub-object of type B
   [[maybe_unused]] B& b = c ; // fine; access sub-object of type B
   // destroy C; destroy sub-object of type B
}

http://coliru.stacked-crooked.com/a/344b937c4b385ead
pure virtual function. In other words, a function that has no definition - only a declaration with 0.

Pure virtual can have an implementation:
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
#include <iostream>

struct A {
    virtual ~A() = default ;
    virtual void pure() = 0;
} ;

struct B : A {} ;

struct C : A {
    void pure() { A::pure(); }
} ;

int main()
{
   // A a ; // error: variable type 'A' is an abstract class
   // B b ; // error: variable type 'B' is an abstract class
   C c ;
   A& r = c;
   r.pure();
}

void A::pure() {
  std::cout << "Hello world\n";
}
Pure virtual can have an implementation
[Obligatory "while that is true, it is a weird feature that may surprise even some experienced C++ programmers" post]
Last edited on
I guess that "during the runtime" there is another behavior between a pure virtual class and a virtual class with a body. No?

No. There is no difference at runtime between a pure virtual function and a non-pure virtual function.

Is there an object for virtual function - when there is nothing for a pure virtual function?

I'm not sure that I understand this question. Creating objects (usually) happens at runtime but if you tried to create an instance of an abstract class the code would not even compile so the difference is not at runtime.
Last edited on
@keskiverto in your example, this is no more a pure virtual function if you define it no?
It's still pure. A is still an abstract class. Any class that inherits from A still needs to override it (unless it also wants to be an abstract class).

The only way you can call it is by qualifying the function call with A:: in front like keskiverto did on line 11.
Why would this be useful? I don't know. I suggest you ignore this quirk for the time being.
Last edited on
Yes, it is a quirk for eating a cake and having it too.

https://en.cppreference.com/w/cpp/language/abstract_class says that the = 0 in the member function declaration is pure-specifier.

It is less about the "purity" of the member function and more about declaring the class being abstract. With the quirk one can provide an abstract class, yet include default implementations for all of its member functions.

I'd guess that the standardization committee does not like "artificial limitations".
Pages: 1234