Search

12.6 — Pure virtual functions, abstract base classes, and interface classes

Pure virtual (abstract) functions and abstract base classes

So far, all of the virtual functions we have written have a body (a definition). However, C++ allows you to create a special kind of virtual function called a pure virtual function (or abstract function) that has no body at all! A pure virtual function simply acts as a placeholder that is meant to be redefined by derived classes.

To create a pure virtual function, rather than define a body for the function, we simply assign the function the value 0.

When we add a pure virtual function to our class, we are effectively saying, “it is up to the derived classes to implement this function”.

Using a pure virtual function has two main consequences: First, any class with one or more pure virtual functions becomes an abstract base class, which means that it can not be instantiated! Consider what would happen if we could create an instance of Base:

Because there’s no definition for getValue(), what would base.getValue() resolve to?

Second, any derived class must define a body for this function, or that derived class will be considered an abstract base class as well.

A pure virtual function example

Let’s take a look at an example of a pure virtual function in action. In a previous lesson, we wrote a simple Animal base class and derived a Cat and a Dog class from it. Here’s the code as we left it:

We’ve prevented people from allocating objects of type Animal by making the constructor protected. However, there are two problems with this:
1) The constructor is still accessible from within derived classes, making it possible to instantiate an Animal object.
2) It is still possible to create derived classes that do not redefine function speak().

For example:

This will print:

Betsy says ???

What happened? We forgot to redefine function speak(), so cow.Speak() resolved to Animal.speak(), which isn’t what we wanted.

A better solution to this problem is to use a pure virtual function:

There are a couple of things to note here. First, speak() is now a pure virtual function. This means Animal is now an abstract base class, and can not be instantiated. Consequently, we do not need to make the constructor protected any longer (though it doesn’t hurt). Second, because our Cow class was derived from Animal, but we did not define Cow::speak(), Cow is also an abstract base class. Now when we try to compile this code:

The compiler will give us a warning because Cow is an abstract base class and we can not create instances of abstract base classes:

C:\Test.cpp(141) : error C2259: 'Cow' : cannot instantiate abstract class due to following members:
        C:Test.cpp(128) : see declaration of 'Cow'
C:\Test.cpp(141) : warning C4259: 'const char *__thiscall Animal::speak(void)' : pure virtual function was not defined

This tells us that we will only be able to instantiate Cow if Cow provides a body for speak().

Let’s go ahead and do that:

Now this program will compile and print:

Betsy says Moo

A pure virtual function is useful when we have a function that we want to put in the base class, but only the derived classes know what it should return. A pure virtual function makes it so the base class can not be instantiated, and the derived classes are forced to define these functions before they can be instantiated. This helps ensure the derived classes do not forget to redefine functions that the base class was expecting them to.

Pure virtual functions with bodies

It turns out that we can define pure virtual functions that have bodies:

In this case, speak() is still considered a pure virtual function (even though it has been given a body, because of the “= 0”) and Animal is still considered an abstract base class (and thus can’t be instantiated). Any class that inherits from Animal needs to provide its own definition for speak() or it will also be considered an abstract base class.

When providing a body for a pure virtual function, the body must be provided separately (not inline).

This paradigm can be useful when you want your base class to provide a default implementation for a function, but still force any derived classes to provide their own implementation. However, if the derived class is happy with the default implementation provided by the base class, it can simply call the base class implementation directly. For example:

The above code prints:

Sally says buzz

This capability isn’t used very commonly.

Interface classes

An interface class is a class that has no member variables, and where all of the functions are pure virtual! In other words, the class is purely a definition, and has no actual implementation. Interfaces are useful when you want to define the functionality that derived classes must implement, but leave the details of how the derived class implements that functionality entirely up to the derived class.

Interface classes are often named beginning with an I. Here’s a sample interface class:

Any class inheriting from IErrorLog must provide implementations for all three functions in order to be instantiated. You could derive a class named FileErrorLog, where openLog() opens a file on disk, closeLog() closes the file, and writeError() writes the message to the file. You could derive another class called ScreenErrorLog, where openLog() and closeLog() do nothing, and writeError() prints the message in a pop-up message box on the screen.

Now, let’s say you need to write some code that uses an error log. If you write your code so it includes FileErrorLog or ScreenErrorLog directly, then you’re effectively stuck using that kind of error log (at least without recoding your program). For example, the following function effectively forces callers of mySqrt() to use a FileErrorLog, which may or may not be what they want.

A much better way to implement this function is to use IErrorLog instead:

Now the caller can pass in any class that conforms to the IErrorLog interface. If they want the error to go to a file, they can pass in an instance of FileErrorLog. If they want it to go to the screen, they can pass in an instance of ScreenErrorLog. Or if they want to do something you haven’t even thought of, such as sending an email to someone when there’s an error, they can derive a new class from IErrorLog (e.g. EmailErrorLog) and use an instance of that! By using IErrorLog, your function becomes more independent and flexible.

Don’t forget to include a virtual destructor for your interface classes, so that the proper derived destructor will be called if a pointer to the interface is deleted.

Interface classes have become extremely popular because they are easy to use, easy to extend, and easy to maintain. In fact, some modern languages, such as Java and C#, have added an “interface” keyword that allows programmers to directly define an interface class without having to explicitly mark all of the member functions as abstract. Furthermore, although Java (prior to version 8) and C# will not let you use multiple inheritance on normal classes, they will let you multiple inherit as many interfaces as you like. Because interfaces have no data and no function bodies, they avoid a lot of the traditional problems with multiple inheritance while still providing much of the flexibility.

Pure virtual functions and the virtual table

Abstract classes still have virtual tables, as these can still be used if you have a pointer or reference to the abstract class. The virtual table entry for a pure virtual function will generally either contain a null pointer, or point to a generic function that prints an error (sometimes this function is named __purecall) if no override is provided.

12.7 -- Virtual base classes
Index
12.5 -- The virtual table

114 comments to 12.6 — Pure virtual functions, abstract base classes, and interface classes

  • Tommy

    Just to say I finally figured out the purpose of pure virtual functions through this guide. Thank you!!!!

  • Anthony

    Hi,

    One tiny typo:

    "Pure virtual functions with bodies
    It turns out that we can define pure virtual functions that ->have also-< bodies:"

  • Spirit

    I am confused as to whether I shalt use interfaces or multiple inheritance.

  • ryder

    Hi Alex:

    I just could not find this comment on your site:

    https://www.learncpp.com/cpp-tutorial/126-pure-virtual-functions-abstract-base-classes-and-interface-classes/comment-page-2/#comment-394744

    Not sure what's going on here.

    I'm reviewing nascardriver's reply but I could not find the commment anymore.

    To nascardriver:

    If you can see this message and if you have a backup of your personal comment: please leave your comments again. I really want to read them.

    Following is my backup notes:

    *** reply to nascardrive

        Thanks for sharing the stackoverflow page. But I cannot comment
        their, so I would like to put my further study
        here. Templateypedef metioned 5 points in this reply.
    **** Point 1

         If virtual memory exists, then we could use the same physical
         address to loaded information stored in that memory at the same
         time. I don't understand this point.

    #+BEGIN_SRC c++
    void fooA()
    {
        std::cout << "Hello, Alex.";
    }

    void fooB()
    {
        std::cout << "Hello, Nascardrive.";
    }
    #+END_SRC

        In the above code, ~fooA~ and ~fooB~ are different functions, but
        according to this explaination:

        > two programs could be loaded into memory and run at the same time

        As you can see, I revise the sentence based on this original one:

        (If virtual memory didn't exist, two programs couldn't be loaded
        into memory and run at the same time,)
        
        In my naive understand, the information of two functions is
        different. How is that possible for those two functions stored in
        the same physical address at the same time?

        I mean, if you compile this program on your computer, if you can
        fly into your RAM at the exactly location of ~fooA~, you will find
        a bunch of 01010. This 0101 is ~"Hello, Alex."~ It should not be
        anything else, like "Hello, Nascardrive."

        What do I forget here?
    *****
    **** Point 2

         Yes, point 2 is what I exepected. At the single moment in our
         world, one memory could only have one information. But
         explanation from this point does not clarify we we need virtual
         memory.
    *****
    **** Point 3

         This point is very interesting! Security issue by using direct
         memory address. I never know this point. How can this even
         happen? How a program using a particular part of meomory
         (physical memory) be able to using the memory that it is not
         assigned to? Can you provide a c++ piece of code to achieve this?
         Or, do you have any reference on this point? I would like further
         do some readings on this topic and share you with my
         understanding.
    *****
    **** Point 4

         This is what I speculated before I read this answer. One program
         (or function) should use one region of memory at one time. What I
         don't understand is how virtual memory massive improve the
         performance?
    *****
    **** Point 5

         I think the reservation mechanism could be also done in physical
         memory address method? Why using virtual memory address could
         solve the physical devices issue?
    *****

    • Hi!

      learncpp went down and has been restored from backups. Some comments were lost.
      I can't seem to find your last comment either, I'll try to do this from memory:
      The link for reference https://stackoverflow.com/a/19349645/9364954

      1.
      Let's say there are 2 programs A and B. Both want their code to be loaded at address 0x4000000.
      Assuming no virtual memory:
      Program A starts and is loaded into memory.
      Program B cannot start, because address 0x4000000 is occupied.
      With virtual memory:
      Program A starts and is loaded into memory.
      Program B starts and is loaded into memory.
      Neither program is using the physical address 0x4000000 (They could, but it's unlikely). But both get loaded at their own virtual version of 0x4000000.
      A single process cannot use the same memory for different things. There is only ever 1 information in 1 memory.

      2/3.

      Without virtual memory, this could work. With virtual memory, each process has their own version of 0x12345678.

      4.
      A process wants memory at address 0x100 and at 0x100000, 1 bytes each.
      Without virtual memory:
      Now there's a lot of memory in between those 2 addresses that's unused and is difficult to use for other purposes, because your new data would have to fit in there.
      With virtual memory:
      The process gets one page of memory for 0x100 and one page of memory for 0x100000. Where these pages are in pysical memory doesn't matter, they can be right after each other, or spread wide apart. The only wasted memory is whatever is unused on those 2 pages. Since it's unlikely that only 1 bytes is used, the amount of wasted memory is little.

      5.
      I don't remember your comment about his one. I know I referred to 2 and 3. If this doesn't help, ask again.

    • Alex

      Hey Ryder,

      As Nascardriver said, a few days worth of comments were lost. I'm working with my host to see if a more recent backup can be located. If so, I'll see if I can merge the missing comments in.

      My apologies for the missing content.

  • lucieon

    Minor typo but I thought I would let you know...
    Don't need the ; here:

  • ryder

    Hi Alex or nascardrive or other people who are interested in this question:

    (to nascardrive: I will thanks for your help on other question, I just still working on them, will update to you when I feel is okay)

    My question:

    What’s the different between const char* and char*?

    Why it cannot be compiled using char* ? as the return type of speak()?

    [/code]
    #include "pch.h"
    #include <iostream>
    #include <string>

    class Animal // This Animal is an abstract base class
    {
    protected:
        std::string m_name;

    public:
        Animal(std::string name)
            : m_name(name)
        {
        }

        std::string getName() { return m_name; }
        virtual  char* speak()   = 0; // note that speak is now a pure virtual function
    };

    class Cat : public Animal
    {
    public:
        Cat(std::string name)
            : Animal(name)
        {
        }

        virtual   char* speak()  { return "Meow"; }
    };

    class Dog : public Animal
    {
    public:
        Dog(std::string name)
            : Animal(name)
        {
        }

        virtual  char* speak()  { return "Woof"; }
    };

    class Cow : public Animal
    {
    public:
        Cow(std::string name)
            : Animal(name)
        {
        }

        virtual  char* speak()  { return "Moo"; }
    };

    int main()
    {
        Cow cow("Betsy");
        std::cout << cow.getName() << " says " << cow.speak() << '\n';
    }

    Severity    Code    Description    Project    File    Line    Suppression State
    Error (active)    E0120    return value type does not match the function type    ConsoleApplication7    
    Error (active)    E0120    return value type does not match the function type    ConsoleApplication7    
    Error (active)    E0120    return value type does not match the function type    ConsoleApplication7    
    Error    C2440    'return': cannot convert from 'const char [5]' to 'char *'    ConsoleApplication7    
    Error    C2440    'return': cannot convert from 'const char [5]' to 'char *'    ConsoleApplication7    
    [code]

    • Hi Ryder!

      Opening code tags don't have a slash in them.

      * Line 8, 12, 24, 35, 46, 55: Uniform initialization
      * @getName should return a const reference. Copying data is slow.
      * @main: Missing return statement

      > What’s the different between const char* and char*?
      const char* is not allowed to be modified. char* is.

      String literals (Lesson 6.8b) are immutable (They are not allowed to be modified).

      When you're returning "Moo", that's an immutable string literal. You're trying to return it as a non-const char*, which would mean that it can be modified. This is a contradiction, so you can't do it.

      • ryder

        > -   Line 8, 12, 24, 35, 46, 55: Uniform initialization

        Thanks for reminding for the uniform initalization when
        constructing the class.

        > @getName should return a const reference. Copying data is slow.

        I agree with you. Indeed I copy from Alex code, maybe we could
        suggest him to improve this point.

        > @main: Missing return statement

        I am sorry to forget put `return 0;` in the main.

        The word "immutable memory" is cool. What's the difference
        between "immutable memory" and a "regular memory". I mean I know
        the former could not be modified. What I want to know is the magic
        of complier: how does the computer know some part of memory is
        "immutable"?

        As I further read your explaination, I start to think:

        if a string is this:

        { "STRING" }

        It means it's an immutable string literal? Am I right?

        At the end of reading your explaination, I write my understanding:

        > What's the different between `const char*` and `char*`?
        > Why it cannot be compiled using `char*`? as the return type of `speak`?

        `const char*` is an immutable string whose memory cannot be
        modified.

        `char*` is a regular string whose memory can be modified.

        In the snippets codes (I provided)

        For example:

        The return thing: `{ return "Moo" }` is an immutable string, which
        cannot be modified. However, the function declaration is `char*`,
        which means it can be modified! That's contradictive to what is
        pass in it, so the complier complain.

        • > how does the computer know some part of memory is
          "immutable"?
          You can address 2^64 bytes. 2^64 bytes are 16 EiB (16777216 TiB). Of course, you don't have that much physical memory. To work around this, your computer uses memory pages, like a book. But some pages can be missing, this allows you to address the entire memory range without actually having that much memory.
          Each page has flags, which specify whether it's memory is readable, writable, and/or executable.
          Your program consists of regions. Each region with it's own purpose (constants, code, data, etc.). The page the regions get loaded into get their flags set accordingly. Eg. constants are in a read-only page, code is in a read/execute-page.
          How does the computer know the flags? This can be either controlled by hardware, which is faster, or by software (Your OS).

          • ryder

            I like your metaphor using a book, but I have some more
                questions. If I want to declare a memory space of 16 EiB using a
                book that has 16 pages. Assumming each page has a size of 1 EiB,
                it should have no problem. However, today's technologies are not
                there yet. We can have a book of 16 pages, but each page only have
                1 PiB. How can this book has a compacity of 16 EiB memory?

                This is my understanding reading your metaphor. We have a 16 pages
                book. But, to claim we have a super big memory machine, we say
                that this 16 pages book missing some pages. In reality, there are
                some missing pages, 1024/(16-1) = 68.2666 pages, in between the
                real pages (Page 1 ~ Page 2). Is this what it mean by "some pages
                are missing."

                If this is ture, what's the purpose of doing this? Indeed, if a
                page is missing, you cannot read or write on that page, so what's
                the purpose of doing so?

            • You can address 16EiB, but not all at once.
              You want to be able to address the full 16EiB, because that's easier than having to care about how much physical memory there is.
              The 16EiB don't fit into your RAM.
              The addresses you see are virtual, ie. they're just aliases for a physical address.
              If you have 1 byte of memory at the virtual address 0x1000 and 1 byte of memory at address 0x500000, then there won't be a huge gap of unused memory. Instead, this memory could be near each other in physical address space. So your 2 bytes don't occupy 0x499000 bytes, but instead, only 2 pages (However much that may be).
              In our book analogy: You have a book with 100 pages, but you want to be able to use 1000 site numbers. You don't need 1000 site numbers at once. The pages don't have numbers on them, so you can write down whatever number you like. If your book is empty and you want a page to have number 782, you can write number 782 and the first physical page of the book. You can write 695 on the second physical page. You have now used a virtual range of 782-695=87 pages, but you have used only 2 physical pages.
              How you choose the next physical page and how you map physical to virtual addresses can have a big impact on performance. Luckily, your hardware/os takes care of that.

              • ryder

                > You can address 16EiB, but not all at once

                What does it mean? If I have a regular memory, e.g., [Corsair
                Vengeance LPX 32GB DDR4 3000 C15 for Intel 100 Series - White](https://www.amazon.ca/Corsair-Vengeance-3000MHz-Desktop-Memory/dp/B01EI5Z8ZE/ref=sr_1_1?s=electronics&ie=UTF8&qid=1548865159&sr=1-1&keywords=RAM&th=1)
                (<https://www.amazon.ca/Corsair-Vengeance-3000MHz-Desktop-Memory/dp/B01EI5Z8ZE/ref=sr_1_1?s=electronics&ie=UTF8&qid=1548865159&sr=1-1&keywords=RAM&th=1>),
                Do you mean that I could address 16EiB's memory using this 32GiB
                memory card?

                > The 16EiB don't fit into
                > your RAM.

                From my understanding: assuming the longest URL ( 2000 characters
                ) that a typical broswer can handle
                (<https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers>). A
                character has a size of 1 byte, so the maximum URL could have a
                maximum size of ( 2000 \* 1 byte = 2000 byte ). Assuming in idea
                condition that the memory we just purchurse on amamzon, i.e. 32
                GiB, we could store ( 34359740000 / 2000 = 17179870 ) URLs in our
                memory. Obviously, we are not able to claim that our memory is
                able to store a data whose size is 16 EiB ( 18446744073.71 GiB =
                19807040628566999040 byte ). However, if we claim that each of
                those URL is another memory whose size is ( 19807040628566999040
                /17179870 = 1152921449846.0697921462735166215 byte =
                1073.741773000052 GiB ). In other word, if we open the broswer and
                open the URL that is written in the memory, and if we could read
                and write stuff on that address (URL), we then claim that we have
                just bought a memory with 16 EiB? Is this what you mean?

                I had hard time in understanding virtual and physical address. It
                seems that there's no virtual memoery because it's just alias for
                a physical memoery. If so, could we just use the term physical
                address in further discussion. Correct me if I miss something
                about virtual address.

                Go back to our book analogy. I don't understand your
                explanation. See, if we have a book with 100 pages. We claim that
                this book has a capcity of saving data whose size is 16 EiB. To
                show other people, we have such a big memory. We need to test
                it. The test is to store 1000 site number ( 1000 URLs)? Each site
                number (URL) has a size of ( 16 / 1000 EiB = 18446744073.71 / 1000
                GiB = 19807040628566999040 / 1000 byte ). So if we open this book
                and read the data on that page, and we found the correct URL, we
                could then claim that we have such a big memory.

                The issue is that we don't have such a big page. In reality, each
                page of that book could only store 1 GiB data. My question is how
                to adress 16 EiB data using this normal memoery?

                • > Do you mean that I could address 16EiB's memory using this 32GiB
                  memory card?
                  Yes

                  > URL
                  That example is correct up to "However, if we claim [...]". I understand the calculation you're doing, but I don't understand what you're trying to show.
                  We never claim to be able to store 16 EiB, but we're able to use addresses 0x00000000'00000000 to 0xFFFFFFFF'FFFFFFFF on a 64 bit machine. But not all at a time.

                  > It seems that there's no virtual memoery because it's just alias for
                  a physical memoery
                  It's not. Virtual addresses are aliases for for physical addresses. Don't mix this up with "when I say 'virtual address' I mean 'physical address'".
                  Each virtual address translates to a physical address. The easiest way of imagining this is a table with virtual addresses on one- and physical addresses on the other side

                  Now, if you want to access the virtual address 0x4000, you look into that table and see that the memory you want to access is at the physical address 0x59F00300.
                  If the virtual and physical memory has the same size, there's no point in doing this, because we could map virtual addresses to their identity (ie. 1 is 1, 2 is 2, etc.).
                  But as you already understood, those memory regions don't have the same size. Your 32 GiB RAM is way smaller than your 16 EiB virtual memory.
                  Here's a table for virtual>physical

                  We have virtual 64 bit addresses which we can use for software. But your 32 GiB hardware only has a range from 0x00000000 to 0xFFFFFFFF. We take the virtual addresses (Only the ones that are in use!) and map them to physical addresses. We can only use a maximum of 0xFFFFFFFF addresses (by count), but the addressable range has increased significantly.

                  > We claim that this book has a capcity of saving data whose size is 16 EiB
                  No. We cannot change the capacity. The capacity stays at 100 pages. We claim that we have more than 100 pages numbers.
                  Let's say the first 50 pages are filled in, we can't add any more content to them. Now you want to write something on page 400. Of course you don't have a 400th page, but you can use 400 as a page number. We write the new content on page 51 (Again, how to choose a new page in important, I'll just take the next free page) and add an entry in our page table

                  The next time you access page number 400, you look in your page table, see that it's on the physical page 51, and access the physical page 51.
                  Virtual addresses aren't about increasing capacity, they're about increasing the addressable range.

                  You as a programmer don't notice anything of the mapping, you only see virtual addresses.

                  • Ryder

                    just a quick note: I am not a programmer. I am just interested in those stuff. I will read your reply carefully and reply to you when necessary. Thank you so much!

                  • ryder

                    Hi Nascardirver:

                    I read you reply and have more questions. But let me summary my
                    question first before I jump into the details:

                    What's the purpose of using such alias, i.e., virtual memory?

                    >> Do you mean that I could address 16EiB's memory using this 32GiB
                    >> memory card?
                    >
                    >Yes

                    Let me remind us the initial question: "Can we address 16 EiB memory
                    using 32 GiB"?

                    I ask this question because my first impression to it is not. You buy
                    a 32 GiB memory card. You could only have that space of memory. Why
                    someone could claim such a big memory. (After reading your comment
                    below, I start to understand what you are saying here. We cannot have
                    such a big memoery card, but it doesn't mean that we could not address
                    a big memoery. Indeed, very small size of memory card, i.e. 10 MiB, we
                    could also address a 16 EiB memory.)

                    >URL That example is correct up to "However, if we claim […]". I
                    >understand the calculation you're doing, but I don't understand what
                    >you're trying to show.

                    I am trying to clear my understanding of this question, i.e., to
                    explain that I could buy a book with a capcity of 32 GiB but able to
                    adress 16 EiB memoery. If you still have question on this point please
                    let me know.

                    >We never claim to be able to store 16 EiB, but
                    >we're able to use addresses 0x00000000'00000000 to 0xFFFFFFFF'FFFFFFFF
                    >on a 64 bit machine. But not all at a time.

                    >> It seems that there's no virtual memoery because it's just alias for
                    >> a physical memoery

                    >It's not. Virtual addresses are aliases for for physical
                    >addresses. Don't mix this up with "when I say 'virtual address' I mean
                    >'physical address'". Each virtual address translates to a physical
                    >address. The easiest way of imagining this is a table with virtual
                    >addresses on one- and physical addresses on the other side
                    >
                    >#+BEGIN<sub>SRC</sub>
                    >virtual     physical
                    >0x00001000  0x00000020
                    >0x00004000  0x59F00300
                    >0xF0000000  0x00001000
                    >#+END<sub>SRC</sub>

                    Why we need alias for physical address? Is that because physical
                    adress is too long? I have experience using bash. One of my favourate
                    functionality of bash is to 'alias' my personal command to reduce my
                    typing work on a terminal.

                    >Now, if you want to access the virtual address 0x4000, you look into
                    >that table and see that the memory you want to access is at the
                    >physical address 0x59F00300.  If the virtual and physical memory has
                    >the same size, there's no point in doing this, because we could map
                    >virtual addresses to their identity (ie. 1 is 1, 2 is 2, etc.).  But
                    >as you already understood, those memory regions don't have the same
                    >size. Your 32 GiB RAM is way smaller than your 16 EiB virtual memory.
                    >Here's a table for virtual > physical
                    >
                    >#+BEGIN<sub>SRC</sub>
                    >virtual              physical
                    >0x0FF05E00'00030000  0x05FA0C00
                    >0x3A001004'80000000  0x00010000
                    >0x00000000'003D0000  0x70044000
                    >#+END<sub>SRC</sub>
                    >
                    >We have virtual 64 bit addresses which we can use for software. But
                    >your 32 GiB hardware only has a range from 0x00000000 to
                    >0xFFFFFFFF. We take the virtual addresses (Only the ones that are in
                    >use!) and map them to physical addresses. We can only use a maximum of
                    >0xFFFFFFFF addresses (by count), but the addressable range has
                    >increased significantly.

                    This will bring an issue: there must be two virtual memory addresses pointing
                    toward the same physical address. What are side effects of this mapping?

                    >> We claim that this book has a capcity of saving data whose size is 16 EiB

                    >No. We cannot change the capacity. The capacity stays at 100 pages. We
                    >claim that we have more than 100 pages numbers.  Let's say the first
                    >50 pages are filled in, we can't add any more content to them. Now you
                    >want to write something on page 400. Of course you don't have a 400th
                    >page, but you can use 400 as a page number. We write the new content
                    >on page 51 (Again, how to choose a new page in important, I'll just
                    >take the next free page) and add an entry in our page table
                    >
                    >#+BEGIN<sub>SRC</sub>
                    >virtual  physical
                    >400      51
                    >#+END<sub>SRC</sub>

                    Why we "foo" ourself using 400 page? Is that because we can delete
                    some old memory when we need more memory space? But why not just use
                    the old memory address?

                    >The next time you access page number 400, you look in your page table,
                    >see that it's on the physical page 51, and access the physical
                    >page 51.  Virtual addresses aren't about increasing capacity, they're
                    >about increasing the addressable range.
                    >
                    >You as a programmer don't notice anything of the mapping, you only see
                    >virtual addresses.

                    Again, what' the purpose of increasing the addressable range?

                    • > Why we need alias for physical address?
                      > what' the purpose of increasing the addressable range?
                      See @templatetypedef's answer over at stackoverflow
                      https://stackoverflow.com/a/19349645/9364954

                      > very small size of memory card, i.e. 10 MiB, we
                      could also address a 16 EiB memory
                      Correct

                      > there must be two virtual memory addresses pointing
                      toward the same physical address
                      Please elaborate

                      > Why we "foo" ourself using 400 page?
                      Maybe page numbers 0 to 399 are reserved for the credits of the book. Maybe page number 400 is a standard page to write the index on.

  • Nitin

    Typo: define these function --> these functions.

  • Quoxa

    Hi,
    probably just a typo:

    In the sentence

    "...they will let you multiply inherit as many interfaces as you like.",

    I think you meant "multiple inherit" instead of "multiply inherit".

  • johnsmith29a

    There is one thing I don't quite understand. Why does an abstract class have a virtual table? *Vptr is set when you instantiate an object and it points to the virtual table of that object's class. Abstract classes can't be instantiated, so why would they need a virtual table?

    You wrote that "Abstract classes still have virtual tables, as these can still be used if you have a pointer or reference to the abstract class". But if I have a pointer to an abstract class, it actually points to an instance of a derived (non-abstract) class, so that derived class's virtual table will be used, right?

  • apple

    Hi Alex,

    Great thanks for this c++ tutorials and it helped me in understanding concepts very quickly. And it will be helpful if you add exercise problems. :) :)

  • jmgonet

    Hi.

    A tutorial like this is hard work, and I just want to say thanks. You helped me today.

    Take care!

  • Benjamin

    Hi,

    this is somewhat a redundant comment, but it was funny for me to see the following:

    I created an abstract class A by defining a pure virtual function. At the same time I made this function final. Clearly, I cannot instantiate an object from the abstract class A. Also I cannot write a class that inherits A, as it cannot override the virtual function.

    With one simple line I wrote an unusable class without creating a compiler error:

    I guess doing something like that nonsense (or is there some weird application?), but I think the compiler should at least give a warning that the developer did something absurd.

  • Nur

    Hello Alex
    Hope you are doing well. I have a question regarding to an Interface class. As you mentioned that pure virtual function should be assigned by the value 0, then it is called pure virtual function. And also you mentioned about pure virtual function with bodies which is outside of class definition for abstract class.Here is a little confusion, so I modified your program( Removed member data-es, access specifiers) to understand in depth the differences between interface and Abstract.
    As we know Interface class should be contained only pure virtual function and with no data members and etc. The question: Is the pure virtual function with body which is outside(with default implementation)considered to be Interface class or abstract class.

    Example for that is below shown Animal class.So, can we consider below Animal class as an Interface class (with pure virtual function with bodies)?

    Example:
    class Animal  
    {
        public:
        virtual const char* speak() = 0;
        virtual ~Animal(){}
    };

    const char* Animal::speak()  // even though it has a body
    {
        return "buzz";
    }
    class Tiger:public Animal// derived class;
    {
      std::string m_name;
      public:
       virtual ~Tiger(){}
       virtual const char*speak()
          {
          return Animal::speak();
          }
    };
    int main()
    {
        Tiger tg;
        std::cout<<tg.speak();
    }

  • Lim Che Ling

    (12.2a. Rule: Apply the override specifier to every intended override function you write.)
    So we don't need to 'overwrite' virtual function in Derived class if the parent is abstract class, right?

    • Alex

      You don't need to, but your derived class will be an abstract class if it derives from an abstract parent and still has pure virtual functions.

  • David

    I'm confused by this: "When providing a body for a pure virtual function, the body must be provided separately (not inline)."

    When a body is provided inline, rather than separately, everything still seems to work as expected.

  • YMK

    Hi Alex,
    Great explanation of interfaces. I have a question though. Is C++ interface classes functionally the same as Swift's protocol? Even though conforming to a protocol doesn't involved inheritance like C++ does, at the crust of it both do the same thing. At least it seems like it to me.

    Kindly give me some insight on this thank you.

    • Alex

      I'm not familiar with Swift, but at a cursory glance, yes, it appears that Swift's protocol serves the same purpose. Java also provides first-class support for this via the interface keyword.

  • Ganesh Bhadane

    Hi Alex,

    I have a question about interfaces. Can I declare interfaces in structure? if yes, then how? And No, why?

    • Alex

      When you say "in structure" you mean using a struct? You can, but you shouldn't. Structs should only be used for plain data (no functions), and interfaces are all functions.

  • Kiran C K

    Hi Alex,
    Is there a way to overload a virtual function in the base class and use only the appropriate function in the derived class? i.e. define only one of the overloaded virutal functions

    • Alex

      Hi Kiran,

      I'm not clear on what you're asking here. Can you clarify?

      • Kiran

        Lets say an abstract class has a function with the same name but with different parameters. In such a case, is there a way that I provide body only for the required function in the derived class? I tried setting the function that I wont use as private but though it is private, it allows the main function to access that method and print the result. Here is the code:

        I am not sure if it is a compiler bug or security flaw or works as expected.

        • Alex

          This is working as expected. You're accesing func() through b, which is of type Base. In class Base, func() is public.

          • Nivetha

            Hi Alex,

            Can you please elaborate on this as it is bit confusing for me.
            In the above case,
            b's vptr will be pointing d's virtual table which will be having Derived::func(int, int) and will be resolved to the same right? But this funtion is declared private in Derived. How can it be accessible?

            • Alex

              Access controls are implemented at a class level and are enforced by the compiler. The fact that the function is private in Derived is irrelevant when accessing the function through a Base pointer. All the compiler sees is that the function in public in Base, and we're accessing through a Base object, so as far as it's concerned, everything is fine.

              • Dani

                I tried to accomplish it through this method:

                and the compiler complaint that by doing so, Base::func1(int, int) was being invalidated, even though it was not deleted on its declaration. Since that was the actual goal of doing so, is there a way to acheive it?

                • Alex

                  C++ won't let you delete a virtual function. There's no direct way to do what you want, but there's an interesting workaround using static_assert that's detailed here.

  • Alex

    The abstract class constructor is still called when you create an (non-abstract) object derived from the abstract class.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]