2

I am new to C++ and have been working through the book C++ Programming in Easy Steps, 5th Edition by Mike McGrath (2017). I am using a Windows 10 computer and the output from c++ -v is at the bottom of this post. Perhaps this is the most relevant compiler version information, I am not sure: gcc version 4.9.3 (x86_64-posix-seh, Built by MinGW-W64 project).

I have made it to the first example in the polymorphism chapter of the book (Chapter 8: page 127) before encountering an error when trying to compile one of his programs. This example is, I believe, supposed to illustrate how "base class pointers can be created binding each derived class by its unique memory address" when there are multiple derived classes.

I provide the contents of the file that I cannot compile, the messages I receive when I try to compile it, and the output I am supposed to receive as shown in the book. I am hoping someone can point out what I am doing incorrectly or point out an error in the code if an error exists. I should say that I have not found even a typo in the book so far and have run maybe 50 of his programs so far without any problems. I have found no erratum related to this issue on the book's website.

Please let me know whether I can provide additional information.

Here are the contents of his file classptr.cpp:

//=============================================
// C++ Programming in easy steps 5ed. [8:134]
//=============================================

#include <iostream>
using namespace std ;

class Base
{
  public:
  //Use default constructor & destructor.
    void Identify( int adr ) const { cout << "Base class called by 0x" << hex << adr << endl ;  }
} ;

class SubA : public Base
{
  // Empty.
} ;

class SubB : public Base
{
  // Empty.
} ;

int main()
{
  Base* ptrA = new SubA ; // or... SubA a ; Base* ptrA = &a ;
  Base* ptrB = new SubB ; // or... SubB b ; Base* ptrB = &b ;
  
  ptrA -> Identify( (int) &ptrA ) ;
  ptrB -> Identify( (int) &ptrB ) ;

  return 0 ;
}

Here are the messages I obtain when trying to compile the program classptr.cpp:

c:\Users\mark_\myCppprograms>c++ classptr.cpp -o classptr.exe
classptr.cpp: In function 'int main()':
classptr.cpp:30:28: error: cast from 'Base**' to 'int' loses precision [-fpermissive]
   ptrA -> Identify( (int) &ptrA ) ;
                            ^
classptr.cpp:31:28: error: cast from 'Base**' to 'int' loses precision [-fpermissive]
   ptrB -> Identify( (int) &ptrB ) ;
                            ^

Here is the output shown in the book. I realize the memory addresses shown in the book will differ from what I get.

c:\Users\mark_\myCppprograms>c++ classptr.cpp -o classptr.exe
c:\Users\mark_\myCppprograms>classptr
Base class called by 0x61ff1c
Base class called by 0x61ff18

Here is what is returned by c++ -v on my Windows 10 laptop:

c:\Users\mark_\myCppprograms>c++ -v
Using built-in specs.
COLLECT_GCC=c++
COLLECT_LTO_WRAPPER=c:/rtools/MINGW_64/bin/../libexec/gcc/x86_64-w64-mingw32/4.9.3/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../../../src/gcc-4.9.3/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/home/Jeroen/mingw-gcc-4.9.3/x86_64-493-posix-seh-rt_v3-s/mingw64 --with-gxx-include-dir=/mingw64/x86_64-w64-mingw32/include/c++ --enable-static --disable-shared --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-isl-version-check --disable-cloog-version-check --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --with-mpc=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --with-isl=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --with-cloog=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --enable-cloog-backend=isl --with-pkgversion='x86_64-posix-seh, Built by MinGW-W64 project' --with-bugurl=http://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -I/home/Jeroen/mingw-gcc-4.9.3/x86_64-493-posix-seh-rt_v3-s/mingw64/opt/include -I/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-zlib-static/include -I/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -I/home/Jeroen/mingw-gcc-4.9.3/x86_64-493-posix-seh-rt_v3-s/mingw64/opt/include -I/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-zlib-static/include -I/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS= LDFLAGS='-pipe -L/home/Jeroen/mingw-gcc-4.9.3/x86_64-493-posix-seh-rt_v3-s/mingw64/opt/lib -L/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-zlib-static/lib -L/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static/lib '
Thread model: posix
gcc version 4.9.3 (x86_64-posix-seh, Built by MinGW-W64 project)

c:\Users\mark_\myCppprograms>
Mark Miller
  • 12,483
  • 23
  • 78
  • 132
  • 1
    An `int` is not guaranteed to be able to hold the address of an object. Use `std::uintptr_t` instead of `int`. Also note that `&ptrA` returns the address of the pointer and not what it's pointing at. – Ted Lyngmo Aug 24 '20 at 06:19
  • 3
    This book... isn't worth what you paid for it. All books have mistakes sure, but this example illustrates that you shouldn't learn C++ from it. – StoryTeller - Unslander Monica Aug 24 '20 at 06:21
  • 2
    @StoryTeller-UnslanderMonica Can you explain why that book is bad, or give the name of a better book? I think that would help OP more than "your book is bad" (no matter how right you may be). And in that vein, for OP; https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – Frodyne Aug 24 '20 at 06:28
  • 1
    @Frodyne - Interesting. By your reasoning I should'nt warn the OP at all unless I'm willing to write an essay. I don't find that very compelling. – StoryTeller - Unslander Monica Aug 24 '20 at 06:34
  • 1
    @StoryTeller-UnslanderMonica No, not at all answer however you want, there is also value in "that is bad". There is just more value in "that is bad because X" or "that is bad, X is better". I was simply trying to encourage a single line or two of explanation or suggestion, but I apologize if it came off as me trying to police your comment. – Frodyne Aug 24 '20 at 06:43
  • @Frodyne Thank you. That looks to be extremely helpful information. – Mark Miller Aug 24 '20 at 06:52

1 Answers1

1

classptr.cpp:30:28: error: cast from 'Base**' to 'int' loses precision [-fpermissive]

Some time ago computers were 32-bit, pointers were 32-bit and int had 32-bits. Nowadays computers are switching to 64-bit, so pointers have 64-bits, but int is still 32-bit (on most platforms). So casting a pointer to an int would remove the upper 32-bits. Most probably using long long instead of int would work.

That's why std::uintptr_t type exists. It's an integer, that has like 64-bits on 64-bit computers and 32-bits on 32-bit computers. Note that int has at least 16 bits, so on a valid (but strange) implementation int can be 16-bit and pointers can have 64-bits, for example. See C data types and 64-bit data models.

ptrA -> Identify( (int) &ptrA ) ;
ptrB -> Identify( (int) &ptrB ) ;

Note that &ptrA takes the address of the pointer itself, not where the pointer it points to.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111