An Insight Into Inheritance, Object Oriented Programming, Run-Time Type Information, and Exceptions PV264 Advanced Programming in C++

Similar documents
Inheritance, Polymorphism and the Object Memory Model

Rvalue References, Move Semantics, Universal References

C++ for System Developers with Design Pattern

Polymorphism. Zimmer CSCI 330

Overview. Constructors and destructors Virtual functions Single inheritance Multiple inheritance RTTI Templates Exceptions Operator Overloading

Overview. Constructors and destructors Virtual functions Single inheritance Multiple inheritance RTTI Templates Exceptions Operator Overloading

05-01 Discussion Notes

Cpt S 122 Data Structures. Course Review Midterm Exam # 2

Increases Program Structure which results in greater reliability. Polymorphism

Rvalue References & Move Semantics

Exception Safe Coding

Exception Namespaces C Interoperability Templates. More C++ David Chisnall. March 17, 2011

Preface to the Second Edition Preface to the First Edition Brief Contents Introduction to C++ p. 1 A Review of Structures p.

Short Notes of CS201

Making New Pseudo-Languages with C++

CS201 - Introduction to Programming Glossary By

void fun() C::C() // ctor try try try : member( ) catch (const E& e) { catch (const E& e) { catch (const E& e) {

Advanced C++ Programming Workshop (With C++11, C++14, C++17) & Design Patterns

15: Polymorphism & Virtual Functions

IS 0020 Program Design and Software Tools

ECE 3574: Dynamic Polymorphism using Inheritance

Object-Oriented Programming

September 10,

Polymorphism. Miri Ben-Nissan (Kopel) Miri Kopel, Bar-Ilan University

Dynamic Binding C++ Douglas C. Schmidt

A polymorphic value-type for C++

Data Abstraction. Hwansoo Han

QUIZ. Write the following for the class Bar: Default constructor Constructor Copy-constructor Overloaded assignment oper. Is a destructor needed?

C++ Programming: Polymorphism

The Four Polymorphisms in C++ Subtype Polymorphism (Runtime Polymorphism) Polymorphism in C

Object Oriented Programming with c++ Question Bank

COMP6771 Advanced C++ Programming

Modernizing legacy C++ code

Exception Handling Alternatives (Part 2)

CPSC 427: Object-Oriented Programming

Axivion Bauhaus Suite Technical Factsheet AUTOSAR

Part X. Advanced C ++

ECE 449 OOP and Computer Simulation Lecture 14 Final Exam Review

COMP6771 Advanced C++ Programming

Part III. Advanced C ++

OBJECT ORIENTED PROGRAMMING USING C++

G52CPP C++ Programming Lecture 16

Database Systems on Modern CPU Architectures

CS11 Advanced C++ Fall Lecture 3

C++ internals. Francis Visoiu Mistrih - 1 / 41

STRUCTURING OF PROGRAM

Runtime Environment. Part II May 8th Wednesday, May 8, 13

Absolute C++ Walter Savitch

2 ADT Programming User-defined abstract data types

Midterm Review. PIC 10B Spring 2018

04-24/26 Discussion Notes

COMP322 - Introduction to C++ Lecture 09 - Inheritance continued

call/cc (call-with-current-continuation): A low-level API for stackful context switching

C++ TEMPLATES. Templates are the foundation of generic programming, which involves writing code in a way that is independent of any particular type.

Run-time Environments

3.Constructors and Destructors. Develop cpp program to implement constructor and destructor.

Run-time Environments

C++ without Classes. CMSC433, Fall 2001 Programming Language Technology and Paradigms. More C++ without Classes. Project 1. new/delete.

JAYARAM COLLEGE OF ENGINEERING AND TECHNOLOGY Pagalavadi, Tiruchirappalli (An approved by AICTE and Affiliated to Anna University)

CMSC 202 Section 010x Spring Justin Martineau, Tuesday 11:30am

Implementing Interfaces. Marwan Burelle. July 20, 2012

Design issues for objectoriented. languages. Objects-only "pure" language vs mixed. Are subclasses subtypes of the superclass?

CE221 Programming in C++ Part 1 Introduction

C++ Yanyan SHEN. slide 1

Exception Handling in C++

C++ Exception Handling 1

Advanced C++ Topics. Alexander Warg, 2017

G52CPP C++ Programming Lecture 13

EL2310 Scientific Programming

A Whirlwind Tour of C++

C++ Inheritance II, Casting

Loci Programming Language. Stephen Cross

Getting the Best From G++

Introduction to C++ Systems Programming

Introduction to C++ Professor Hugh C. Lauer CS-2303, System Programming Concepts

Welcome to Teach Yourself Acknowledgments Fundamental C++ Programming p. 2 An Introduction to C++ p. 4 A Brief History of C++ p.

(12-1) OOP: Polymorphism in C++ D & D Chapter 12. Instructor - Andrew S. O Fallon CptS 122 (April 3, 2019) Washington State University

VIRTUAL FUNCTIONS Chapter 10

What will happen if we try to compile, link and run this program? Do you have any comments to the code?

Resource Management With a Unique Pointer. Resource Management. Implementing a Unique Pointer Class. Copying and Moving Unique Pointers

CS 485 Advanced Object Oriented Design. Enum. Spring 2017

CGS 2405 Advanced Programming with C++ Course Justification

CSE 374 Programming Concepts & Tools. Hal Perkins Fall 2015 Lecture 19 Introduction to C++

Francesco Nidito. Programmazione Avanzata AA 2007/08

Processes. Johan Montelius KTH

CS

Extending Classes (contd.) (Chapter 15) Questions:

UNDEFINED BEHAVIOR IS AWESOME

TPF Users Group Spring 2005

Object Model. Object Oriented Programming Spring 2015

QUIZ on Ch.5. Why is it sometimes not a good idea to place the private part of the interface in a header file?

Francesco Nidito. Programmazione Avanzata AA 2007/08

Interview Questions of C++

C++ Coding Standards. 101 Rules, Guidelines, and Best Practices. Herb Sutter Andrei Alexandrescu. Boston. 'Y.'YAddison-Wesley

G Programming Languages Spring 2010 Lecture 9. Robert Grimm, New York University

A process. the stack

Announcements. CSCI 334: Principles of Programming Languages. Lecture 18: C/C++ Announcements. Announcements. Instructor: Dan Barowy

Qualified std::function signatures

dewhurst_index.qxd 10/16/02 1:54 PM Page 309 Index

VALLIAMMAI ENGINEERING COLLEGE

Transcription:

An Insight Into Inheritance, Object Oriented Programming, Run-Time Type Information, and Exceptions PV264 Advanced Programming in C++ Nikola Beneš Jan Mrázek Vladimír Štill Faculty of Informatics, Masaryk University Spring 2019 PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 1 / 35

Motivation C++ seems like magic sometimes in fact it is just large C++17 standard is roughly 1600 pages clang is roughly 600 k lines of C++ code and that is just the frontend (it uses LLVM, 800 k lines of code, for optimisation and code generation) another 10 k of standard library and 8 k of runtime library (in case of libc++/libc++abi from LLVM) and designed for performance one of main principles is that language features should have little to no performance cost until they are used this guides design of features such as virtual functions, multiple inheritance, exceptions let us now look into some details of the language PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 2 / 35

Function names in C++ C++ functions can be overloaded, but in the assembly function names have to be unique names are mangled, mangled names are unique mangling not defined by standard, depends on compiler/platform (gcc/clang/icc use Intel style mangling) mangled names contain fully qualified name, argument types _ZN3foo3barEv = foo::bar() _ZN3foo3barEi = foo::bar(int) theoretically, mangled names can be called directly from C mangling can be prohibited by using extern "C": namespace foo { extern "C" void bar( int ) { /*... */ } } bar will be callable directly from C, namespace is ignored not recommended to put extern "C" functions in namespace names can be demangled using c++filt (on Linux) PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 3 / 35

Standard Layout Classes simple classes that have precisely defined layout can be written to a file and read by a program in another programming language have compatible C counterparts members appear in the class in order of appearance in definition, but there can be padding to ensure alignment requirements of some types on x86_64, primitive types are usually aligned so that their address is a multiple of their size generalisation of C++98 Plain Old Data (POD, C-style structs) no virtual functions, virtual base classes, only standard layout data, no mixed access control,... can have (standard layout) base classes non-static data only in one class more precisely on cpp reference PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 4 / 35

In-Memory Layout of Standard Layout Classes struct A { int a1; int a2; }; struct B { A a; int b; }; struct C : A { int c; }; struct A a1 a2 struct B struct A a.a1 a.a2 b struct C struct A a1 a2 c C is not standard layout B and C can have the same in-memory layout (gcc, clang) PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 5 / 35

Empty Base Class Optimisation struct E { }; E struct A { E e; int a; }; A E (pad) a struct B : E { int b; }; B b an empty class has size 1 however, inheriting from an empty class does not increase size note: B is standard layout PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 6 / 35

Weird Behaviour of Zero-Sized Arrays C allows zero-sized arrays, C++ does not, but GCC & clang support it they are used at the end of variably-sized structures, mainly in POSIX struct A { }; struct B { int arr[0]; }; static_assert( sizeof( A ) == 1 ); static_assert( sizeof( B ) == 0 ); zero-sized array has size 0 putting zero-sized array in an otherwise empty struct results in struct of size 0 PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 7 / 35

Class Member Functions in the compiled code, a member function is roughly 1 equivalent to a function that takes an additional first parameter pointer to this struct X { int x; int foo( int y ) { return x + y; } }; // code generated by foo is similar to code generated by: int X_foo( X *this_, int y ) { return this_->x + y; } defines function _ZN1X3fooEi in assembly, it demangles to X::foo(int) mangled the same as foo( int ) in namespace X calling is more complex for virtual member functions but a member function pointer is not the same as a function pointer member function pointer must be able to call a virtual function 1 They can have different calling conventions, but not on x86_64 PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 8 / 35

Virtual Member Functions In object oriented programming it is often necessary to be able to call a function of a derived class through a pointer (or reference) with the type of the base class. struct Base { virtual void foo() { std::cout << "Base" << std::endl; } virtual ~Base() { } }; struct Derived : Base { void foo() override { std::cout << "Derived" << std::endl; } }; int main() { std::unique_ptr< Base > b( new Derived() ); b->foo(); // calls Derived::foo(); } PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 9 / 35

Virtual Functions Implementation It is not possible to detect at compilation time which version of the virtual function should be called. has to be decided at runtime instead (single) dynamic dispatch each class that has any virtual functions contains a virtual function table (vtable) pointer an additional (usually first) member of the class points to an array of function pointers this array contains pointers to the actual implementations of virtual functions to be used see info vtbl OBJECT in GDB vtable pointer is set in the constructor when a member function is called the compiler inserts code that 1 loads the vtable 2 finds the appropriate function pointer 3 calls this function PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 10 / 35

Virtual Table struct Foo { virtual ~Foo() {}; virtual void f(); int x; }; struct Bar : Foo { void f(); virtual void g(); int y; }; struct Bar struct Foo vptr x for Foo y static memory (allocated at program load vtable for Bar vtable for Foo type info for Bar type info for Foo Bar::~Bar() Foo::~Foo() Bar::~Bar() Foo::f() Foo::~Foo() Foo::f() Bar::g() virtual tables are shared by all instances of a given class PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 11 / 35

Virtual Functions Example struct Base { virtual int foo() = 0; virtual int bar() = 0; }; struct Derived : Base { int foo() override { return 1; } int bar() override { return 2; } }; void f( Base &x ) { cout << x.bar(); } // f's implementation is roughly equivalent to (in clang): void f_lowlevel( Base &x ) { using BarPtr = int (*)( Base * ); BarPtr *vptr = *reinterpret_cast< BarPtr ** >( &x ); BarPtr barptr = vptr[ BAR_OFFSET ]; // 1 for bar cout << barptr( &x ); // 0 for foo } PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 12 / 35

Multiple Inheritance I class can have multiple base classes, all of them can define members base classes are usually at the beginning of the object, one after another struct A { long a; virtual void f(); virtual ~A() {} }; struct B { long b; virtual void g(); virtual ~B() {} }; struct C : A, B { long c; void f() override; }; struct D : B, A { long d; void f() override; }; C A vptr for A a B vptr for B b c D B vptr for B b A vptr for A a d PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 13 / 35

Multiple Inheritance II Casts struct A { long a; virtual void f(); virtual ~A() {} }; struct B { long b; virtual void g(); virtual ~B() {} }; struct C : A, B { long c; void f() override; }; struct D : B, A { long d; void f() override; }; C c; D d; A &ac = c; A &ad = d; // (1) C &cac = dynamic_cast< C & >( ac ); // (2) D &dad = dynamic_cast< D & >( ad ); cast to base class (1) might require adjusting pointer by offset (in case of ad) cast to derived class should be performed by dynamic_cast checks that the object is really a part of the object of target type performs pointer adjustment returns nullptr (for pointers) or throws std::bad_cast (for references) in case of type failure PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 14 / 35

Multiple Inheritance III Dynamic Dispatch struct A { long a; virtual void f(); virtual ~A() {} }; struct B { long b; virtual void g(); virtual ~B() {} }; struct D : B, A { long d; void f() override; }; D d; d.f(); // (1) A &ad = d; ad.f(); // (2) (1) is a normal dynamic dispatch, but (2) is more complicated: ad points to the A-part of D but D::f expects this to point to D cannot be called directly offset could be stored in vtable, but it would need to be checked for any virtual call slows code even if it does not use multiple inheritance! vtable in A-part of D contains pointers to wrapper functions that: 1 adjusts the pointer by constant offset 2 performs non-virtual call to the actual implementation B-part vtable of D contains member function pointers directly as PV264: Inheritance, OOP, it RTTI, is aligned Exceptions with D Spring 2019 15 / 35

Virtual Inheritance I basic_istream (B) virtual ios_base basic_ios (A) basic_iostream (D) virtual basic_ostream (C) if two base classes (B, C) of class D share common base class (A), then A is duplicated in D duplication can be avoided by making B and C inherit from A virtually the object hierarchy of such a shape needs to be carefully designed PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 16 / 35

Virtual Inheritance II struct A { long a; virtual void f(); virtual ~A() {} }; struct B : virtual A { long b; void f() override; }; struct C : virtual A { long c; virtual void g(); }; struct D : B, C { long d; void g() override; }; D B chunk vptr for B b C chunk vptr for C c d A vptr for A a this is how clang does it, it can differ apart from virtual functions, virtual table contains offsets of parts of the struct and again, some virtual functions might be called through wrappers but some wrappers might use dynamic offset PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 17 / 35

Construction and Destruction Order Construction order of class with virtual functions 1 construction starts from the base class(es) in order of their appearance, if there are multiple as if the constructor function first called constructors of base classes 2 virtual table pointer(s) are set to point to virtual table(s) of the currently constructed object 3 initializer sections are run 4 constructor body is run in case of virtual inheritance, there are also special temporary vtables that are set in base classes while they are being constructed PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 18 / 35

Construction and Destruction Order Destruction order of class with virtual functions 1 virtual table pointer(s) are set to point to virtual table(s) of the currently destructed object 2 destructor body is run 3 member data destructors are run 4 base destructors are run (in reverse order of appearance) each of them will reset the appropriate vtable pointers to its vtable PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 19 / 35

A Note on Destructor Count how many destructors does a class have? 3 1 deleting object destructor called by delete foo expression (D0) 2 complete object destructor deletes all data members and all base classes (including virtual) (D1) 3 base object destructor deletes all data members and all non-virtual base classes (D2) destructors D2 and D1 are the same if there are no virtual base classes destructor D0 first destroys the object (using D1) then calls operator delete to free the memory operator delete can be overloaded in a class, so this ensures the right one is called (operator new can also be overloaded in a class) note: not C++ standard, this is Intel ABI (clang on Linux, gcc) PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 20 / 35

What About Constructors? similarly, class has a complete object constructor (C1), a base object constructor (C2) that is called from the descendant s constructor, and an allocating object constructor (C3) again C1 and C2 are the same unless virtual inheritance takes place allocating constructor/destructor might be missing PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 21 / 35

Member Function/Data Pointers normal data and function pointers are essentially the same thing address of memory where data or code is stored (on modern architectures) but it can be useful to have pointers into a class, or to a function of a class how? int Foo::*a a pointer to data member of type int that belongs to class Foo and is called a void (Foo::*f)( int ) a pointer to member function of Foo that returns void and gets int; the pointer is called f may not really be an address implementation can differ for non-virtual functions usually contains address directly for pointer to virtual member function it is necessary to do vtable lookup by function index in case of multiple inheritance, offset to the right vtable is also needed PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 22 / 35

Member Function/Data Pointers example struct Foo { int bar(); int baz() const; }; int main() { int (Foo::*pa)() = &Foo::bar; // & is necessary // pointer to const member function int (Foo::*pb)() const = &Foo::baz; Foo f; Foo *fptr = &f; } int x = (f.*pb)(); // using member function pointer int y = (fptr->*pa)(); // the same on pointer PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 23 / 35

Exceptions exceptions are important for handling errors (such as resource allocation failures) in a clean way repeated manual error checking can be avoided normal control-flow of functions is not cluttered but they also come at cost to readability error handling code can be far from error producing code to speed they are slower if an error occurs still, code with exceptions used for rare errors will be probably better readable there are many possibilities to implement exceptions checkpointing CPU registers are saved before a function that can throw is executed, restored if exception is raised (old) zero-cost exceptions should have no performance overhead compared to code without error checking PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 24 / 35

Zero-Cost Exceptions under normal circumstances no exception-related code is executed handled by C++ runtime library implementation can differ, clang/libc++abi implementation for x86_64 Linux is described here libsupc++ from GCC works similarly when throw is executed: 1 an exception object is allocated (on heap, or in emergency storage = global variable) 2 the unwinder library is invoked to handle stack search and actual transfer of control (unwinding) PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 25 / 35

Unwinding Basics I unwinder is provided by the platform, it is not C++ specific extensively uses metadata tables generated by the compiler to find boundaries of stack frames which function corresponds to which stack frame how to search for handlers in given function and frame cooperates with language s runtime library to find handler language defines personality routine that is called by the unwinder to find handlers personality uses metadata tables for given function (found by unwinder) to find the right handler PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 26 / 35

Unwinding Basics II two kinds of exception handlers catch handlers end exception propagation, resolve exception catch exception specification cleanup handlers perform cleanup, exception propagation continues afterwards call destructors triggered only if a catch handler is found 2 which catch handler is appropriate is detected from run-time type information (RTTI) that encodes the inheritance hierarchy cost comes from cost of actual unwinding and related metadata search and decoding cost of inspecting the type hierarchy of the exception 2 not specified by standard but common on Linux/Unix PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 27 / 35

Exception Specification (throw(...), noexcept) int foo() throw ( std::bad_alloc ); int bar() noexcept; throw(), throw(exception types,...) specifies that function is allowed to throw only specified types throwing any other type results in termination of program deprecated in C++11 second version removed in C++17, first made equivalent to noexcept PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 28 / 35

Exception Specification (throw(...), noexcept) int bar() noexcept; template< typename T > int baz() noexcept( std::is_nothrow_constructible< T >::value ); noexcept specifies the function is not allowed to throw not checked by the compiler, but throwing from noexcept function will terminate the program (using std::terminate) compiler-generated default constructors, move and copy constructors are noexcept by default unless appropriate base class or member constructors are not destructors are noexcept unless explicitly marked otherwise noexcept( EXPR ) specifies function is not allowed to throw if EXPR evaluates to true noexcept is equivalent to noexcept(true) PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 29 / 35

Implications of noexcept certain operations can be safely performed only if a function is noexcept vector can use move construction when growing only if move constructor is noexcept exception in move constructor would leave vector in inconsistent state the presence of noexcept can impact performance move constructors should be noexcept if possible PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 30 / 35

Uncaught Exception Handler if an exception is not caught std::terminate is called std::terminate defaults to killing the program, but can be customised std::set_terminate useful for logging exceptions should not try to restore execution (catch is for that) PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 31 / 35

Run-Time Type Information I underlying mechanism for the implementation of dynamic_cast and exception matching in catch clauses #include <typeinfo> // necessary for use of typeid... auto &tint = typeid( int ); // (1) auto &texpr = typeid( 1 + 1 ); // (2) Foo x; // Foo has virtual functions auto &tfoo = typeid( x ); // (3) typeid(arg) returns constant reference to std::type_info object representing type of its argument if arg is a type, returned type_info describes this type (1) if arg is an expression of apolymorphic type, type_info of runtime type of this exception is returned (3) polymorphic type = has virtual method(s) otherwise type_info for static type of the expression is returned (2) PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 32 / 35

Run-Time Type Information II std::type_info defines the name method that is used to get the (implementation defined) name of the type on Linux a part of the mangled name operators ==,!= for checking if the corresponding types are equal not constructible, copyable stored in static memory (generated by compiler) pointer to type_info is present in virtual function table of polymorphic objects std::type_index hashable and comparable wrapper around type_info that can be used as a key for associative maps (std::map, std::unordered_map) PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 33 / 35

Multiple Dispatch (Multimethods) virtual functions provide single dispatch the function to be called depends on the dynamic type of one parameter (the current object, *this) multiple dispatch: the function depends on the dynamic type of multiple parameters; why is it useful? interaction between various kinds of objects (imagine a computer game with weapons and monsters or a vector graphics library that computes intersection of shapes) some languages support multiple dispatch natively Common Lisp, Perl 6, C# 4.0,... other languages have library support for multiple dispatch C, C++, Java, Perl, Python,... how to emulate multiple dispatch in C++? dynamic_cast multidimensional virtual tables for double dispatch: visitor pattern PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 34 / 35

Visitor Pattern base element class Element one purely virtual method accept(visitor&) base visitor class Visitor a virtual method visit(concreteelement&) for each concrete child of Element children of Element override accept as follows: struct Dragon : Element { void accept(visitor& v) override { v.visit(*this); } }; children of Visitor may override its virtual methods struct Axe : Visitor { void visit(dragon&) override { /*... */ } void visit(troll&) override { /*... */ } //... }; PV264: Inheritance, OOP, RTTI, Exceptions Spring 2019 35 / 35