Week 1
Week 1
Oriented Systems
Design Using C++
C OM P- 34 00 - 30 - R - 20 25W
D R . A B D U L R A U F G I D A D O W I T H E X A M P L E S A N D F I G U R E S F R O M
S T R O U S T R U P , B J A R N E ( 2 0 2 3 ) . A T O U R O F C + + , T H I R D E D I T I O N . A D D I S O N -
W E S L E Y P R O F E S S I O N A L , B O S T O N , M A . A N D P A U L P . S L I D E S
The work that led to C++ started in the fall of 1979 under the name
‘‘C with Classes.’’ Here is a
simplified timeline:
started as an
created by Bjarne
The C++ programming enhancement to the C originally called C with
Stroustrup at Bell
language was: programming Classes
Labs in 1979
language
D R . A B D U L R A U F G I D A D O W I T H E X A M P L E S A N D F I G U R E S F R O M
S T R O U S T R U P , B J A R N E ( 2 0 2 3 ) . A T O U R O F C + + , T H I R D E D I T I O N . A D D I S O N -
W E S L E Y P R O F E S S I O N A L , B O S T O N , M A . A N D P A U L P . S L I D E S
ISO Standards
NOTE: C ++ does not “import” all of C —only specific components of the C standard are “imported”.
• Don’t try to force people [to use constructs they don’t want or need].
D R . A B D U L R A U F G I D A D O W I T H E X A M P L E S A N D F I G U R E S F R O M
S T R O U S T R U P , B J A R N E ( 2 0 2 3 ) . A T O U R O F C + + , T H I R D E D I T I O N . A D D I S O N -
W E S L E Y P R O F E S S I O N A L , B O S T O N , M A . A N D P A U L P . S L I D E S
Language Design Objectives (con’t)
WARNING!
• C++ is a very rich, powerful language.
• Know you won’t learn it the day before a test or an assignment!
People that have tried to do this, typically find themselves
dropping the course.
• You will need to keep up with the readings, assignments,
studying, and practice programming throughout this course to
be successful.
C++ Today (con’t)
Modern
• full static-type checking
• the ability to overload functions including for operators, e.g., ==, <,
++, ()
• generic programming and static polymorphism
Programming Paradigms
• Imperative Paradigm
• Procedural Paradigm
• Modular Paradigm
• Data Abstraction
• Object-Based Paradigm
• Object-Oriented Paradigm
• Generic Paradigm
• Functional Paradigm
• Multiparadigm Programming
Language
Imperative Paradigm
• 1 #include "tcxxpl-2p5p1.hxx"
• 2
• 3 struct Bad_pop { };
• 4
5 void f()
6 {
7 Stack::stack s1 = Stack::create(); // make a new stack
8 Stack::stack s2 = Stack::create(); // make another new stack
9
Modular Paradigm (con’t)
w01/tcxxpl-2p5p1-f.cxx
10 Stack::push(s1, 'c');
11 Stack::push(s2, 'k');
12
if (Stack::pop(s1) != 'c') throw Bad_pop();
13
14 if (Stack::pop(s2) != 'k') throw Bad_pop();
15
Stack::destroy(s1);
16
Stack::destroy(s2);
17
18 }
w01/tcxxpl-2p5p1-f-c.cxx
Stack_push(s1, 'c');
10
11 Stack_push(s2, 'k');
12
if (Stack_pop(s1) != 'c') handle_error();
13
14 if (Stack_pop(s2) != 'k') handle_error();
15
Stack_destroy(s1);
16
Stack_destroy(s2);
17
18 }
Modular Paradigm (con’t)
With the above stack code, one can only have a stack of chars.
To make a stack of doubles one must:
• create a new module,
• a new stack struct, and
• functions implementing the new type of stack.
Possible solutions to avoid having to rewrite the stack just to change the data type
used:
• use object-based/oriented programming, or,
• use object-based/oriented programming with generic/template programming.
Generic code is turned into real code by substituting real types and
constant values for each parameter. This process in C ++ is called template
instantiation.
Generic Paradigm (con’t)
Since C++ is a statically-typed language, any and all use of generics must be
fully evaluated and determined at compile-time.
In C++, generic use requires defining and using templates. Just as functions have
arguments, templates have parameters.
This code shows that min<T>() is a pattern using the (type) placeholder T.
In main() the pattern is instantiated when min() is called with two
arguments having exactly the same type.
Generic Paradigm (con’t)
• w01/generic2-eg.cxx
1 template <typename T>
2 struct ListNode
3 {
4 ListNode<T> *prev;
5 ListNode<T> *next;
6 T datum;
• 7 };
• 8
Generic Paradigm (con’t)
w01/generic2-eg.cxx
9 int main()
10 {
11 // Generate ListNode where T is an int...
12 ListNode<int> a;
13 a.prev = a.next = nullptr;
14 a.datum = 34;
15
16
17 // Generate ListNode where T is a ListNode<char>...
18 ListNode< ListNode<int> > b;
19 b.prev = b.next = nullptr;
20 } b.datum = a;
Generic Paradigm (con’t)
Note that the above code computes the type of MY_INT at compile-time.
Functional Paradigm
The functional programming paradigm describes the evaluation of code using
pure functions.
That one can even use this paradigm in C++ was not by design.
Multiparadigm Programming Language
3 First Steps
Assumptions
Coding Requirement
Hello World!
Using the std Namespace
Default Streams
Using The Stream Operators
I/O For User-Defined Types
Error Detection For IOStreams
Compiling and Linking Code
Assumptions
Given this
course’s
prerequisites,
you already know how to
it is assumed: program in Java, and,
you already know how to
program in C.
DR . ABDU LRAU F G ID ADO WI T H EX AM PLE S AND
F IG URES F ROM STROUSTR UP, BJ ARN E (20 2 3) . A TOUR
O F C+ +, T H I RD E DI T I ON . ADD IS O N- WE S LE Y
PRO F E SS I O NAL , BO S T O N, M A. AN D PAUL P. S LI DE S
Assumptions (con’t)
C is mostly a subset of C++ as most valid C programs are also valid C++
programs, however:
• not all valid C programs are valid C++ programs,
• in C++ the C Standard Library in the std namespace,
• for namespace and differences between C and C ++, using a standard C
include header requires:
1. dropping the .h from its file name, and,
2. prefixing a ’c’ to the file name
• For example, “<stdio.h>” becomes “<cstdio>” in C++.
• Do not directly include a standard C header file in C ++.
• If you must include a C header in C++ not part of the C Standard Library that
was not designed for use with C++ but whose contents can be compiled by a
C++ compiler, then enclose such within an extern "C" block so all symbols
within that header have C linkage.
This is a C++ course!
Unless otherwise explicitly stated/written, in this course you are required to use C ++
language and library features and constructs over any C language and library features
Coding Requirement
that can be used to accomplish the same.
Hello World!
• The traditional minimal programthat outputs “Hello World!” using the C Standard Library in C ++ looks like:
w01/hello-1.cxx
• 1 #include <cstdio>
• 2
3 int main()
4 {
5 std::printf("Hello World!\n");
• 6 }
Hello World! (con’t)
• Doing so allows one to avoid explicitly writing std:: in front of all symbol names that are in the std
namespace.
Using the std Namespace (con’t)
• As your C ++ code skills improve, move your use of “using namespace std;” to smaller scopes (e.g., inside
functions only). For example:
• w01/hello-4.cxx
• 1 #include <iostream>
• 2
3 int main()
4 {
5 using namespace std;
6 cout << "Hello World!\n";
• 7 }
• Amongst other things, this will help reduce ambiguous symbol compiler errors.
Using the std Namespace (con’t)
• As your skills further improve, avoid using “using namespace std;” in favour of usingthe using directive to tell
the compiler whereto look for specific symbols explicitly, e.g.,
• w01/hello-5.cxx
• 1 #include <iostream>
• 2
3 int main()
4 {
5 // When cout is used w/o qualification, get it from std...
6 using std::cout;
7 cout << "Hello World!\n";
• 8 }
Default Streams
Unlike their C equivalents, in C++ cin, cout, cerr, and clog are instances of the
std::istream and std::ostream classes with additional capabilities.
IOStream Reading and Writing Operators
The capabilities of C++ stream classes are extensive. Their capabilities can be
easily used using overloaded bit-shift operators:
• use operator>> to read data from a stream, and,
• use operator<< to write data to a stream.
The C ++ Standard defines many overloaded << and >> operators including:
• bool, char, char* and std::string
• short and unsigned short
• int and unsigned int
• long and unsigned long
• long long and unsigned long long (C++11)
• float, double, long double void*
• std::string
I/O For User-Defined Types
If any error occurs on a stream in C++, no further I/O occurs on that stream object
until the error is cleared.
Error Detection For IOStreams (con’t)
When using GNU GCC’s g++ compiler, use the following options to compile your C++
code, e.g. if the source code is in file.cxx use:
ISO Level g++ Command Line Options
C++98 - s t d = c +98 -Wa l l -We x tra -We rr o r - W o l d - s t y le - c a s t fi le .cxx
C++11 - s t d = c +11 -Wa l l -We x tra -We rr o r - W o l d - s t y le - c a s t fi le .cxx
C++14 - s t d = c +14 -Wa l l -We x tra -We rr o r - W o l d - s t y le - c a s t fi le .cxx
C++17 - s t d = c +17 -Wa l l -We x tra -We rr o r - W o l d - s t y le - c a s t fi le .cxx
C++20 - s t d = c +20 -Wa l l -We x tra -We rr o r - W o l d - s t y le - c a s t fi le .cxx
C++23 - s t d = c +23 -Wa l l -We x tra -We rr o r - W o l d - s t y le - c a s t fi le .cxx
NOTE: C++23 is not yet an official standard but has already been approved in 2023
and will be official very soon. Many compilers regularly release experimental support
for upcoming standards.
Compiling and Linking Code (con’t)
When using a debugger, remember to compile the code with debug symbols, e.g., use
one of these compiler options:
• -g, -g1, -g2, -g3, -ggdb
NOTE: This course will use GCC version 13.2 or higher and will focus on C ++ code
conforming to the C++20 standard as well as newer upcoming C ++ standard features.
Outline
4 a uto
Variable Declarations
With and Without a return Type
decltype(auto)
auto : Variable Declarations
• Prior to C ++11, the auto keyword was used to declare variables with automatic storage duration, e.g., on the call stack.
Since such was (and remains) the default storage duration for variables declared at block scope or in function parameter list s, auto
was almost completely unused (in C and in C ++).
auto : Variable Declarations (con’t)
Examples:
• auto i = 5; // i's type deduced to be int
• auto const& j = i; // j's type is int const&
• auto k = 3.2F; // k's type is float
auto : Variable Declarations (con’t)
Know that Template Argument Deduction (TAD) type deduction is not simple overall,
e.g., see [1, Template Argument Deduction]. The design of TAD’s rules are to do the
“right thing” (most of the time) —so one doesn’t have to become a language expert
to make use of such.
auto when used must always be initialized by an expression whose resulting type is the
type that is deduced —or a compiler error results.
This is true for all uses of auto —not just variable declarations.
auto : Variable Declarations (con’t)
Type-deduced auto can appear in many contexts:
• C++11: in a variable declaration
• C++11: as a function’s return type provided the return type is specified as a suffix return
type
• C++14: as a function’s return type without a provided suffix return type
• C++14: as a function parameter type of a lambda function (implies the lambda function is
a function template)
• C++17: as a template parameter for a non-type template parameter
• C++17: in structured binding declarations
• C++20: as a placeholder for a type after a concept constraint, e.g., as a function
argument (implies the function is a function template)
• C++23: as a simple type specifier of an explicit type conversion, e.g., auto(expr) and
auto{expr}.
auto : With and Without a return Type
• auto ispermitted to be usedas the return type of a function —provided the function
provided the return type at the endof the function ”prototype” portion, e.g.,
• w01/auto-suffix-return.cxx
• Suffix return types were add to C++11 to allow code to be written that wasextremely difficult or impossible to write, e.g.,
• w01/func-template-suffix-return.cxx
1 template <typename T, typename U>
2 auto my_func(T t, U u) ->
3 decltype(t+u) // return type is whatever type t+u is
• 4 {
• 5 return t+u;
• 6 }
auto : With and Without a return Type (con’t)
• Lambdafunctions in C++11 have an auto return type with an optional suffix return type if the compiler can deducethe return type, e.g.,
• w01/lambda1.cxx
1 [](int a, float f) // this is a lambda function with two parameters
2 {
3 return a + f + 5.3; // return type is deduced to be double
• 4 }
• If thereis no return statement, then the lambda return type is deducedto be void.
auto : With and Without a return Type (con’t)
• A suffix return type can be specified with a lambda function bywriting such after the function parameter list, e.g.,
• w01/lambda2.cxx
1 [](int a, float f) -> float // set return type to be float
2 {
3 // no type deduction for return type occurs
4 return a + f + 5.3; // double result is implicitly cast to float
• 5 }
auto : With and Without a return Type (con’t)
• Similarly to lambda functions in C++11, starting with C++14, auto is permitted to be usedas the return type of any function without a
specified suffix return type, e.g.,
• w01/auto-return.cxx
1 auto func2(int i, double d)
2 {
3 return i + d; // deduced return type is double
• 4 }
decltype(auto)
Instead of using template argument deduction rules to determine the type, decltype(auto)
uses the type determined by decltype(expression) where expression is the expression
associated with decltype(auto).
decltype(expression) Type
Given an expression, E, associated with an decltype(auto) variable, or,
decltype(auto)-return with no suffix return type, the type is determined as the
resulting decltype(auto)
type of E. (con’t)
Template Argument Deduction v. decltype(auto)
Template argument deduction (TAD) differs from decltype(auto) as follows:
• TAD is a deductive process; decltype(auto) is not
• with TAD, if the deduced type is a forwarding reference (i.e., an rvalue
reference), the deduced type will be adjusted from an rvalue reference to be
decltype(auto)
a value (con’t)
type (i.e., a type with no reference), e.g., T&& is changed to T
Only in (rare) cases when one must preserve the exact type of an
expression, use decltype(expression) or decltype(auto) since using auto
will change rvalue reference types in to value types.
Outline
Can only be used with objects declared at namespace, block, and static data members.
Storage Durations (con’t)
All names not specified as having external, module, or internal linkage have no linkage.
Internal Linkage
A name that can only be referred to from all scopes in the current translation
unit. These names declared at namespace scope have internal linkage:
• variables, variable templates [C++14], functions, static function templates
• data members of anonymous unions
• non-Linkage (con’t)
volatile non- template non-inline non-exported
const-qualified/constexpr variables not declared extern and don’t
otherwise have external linkage
If first declared at block scope, all variables declared extern and all names of functions.
Module Linkage
Names that can only be referred to from scopes in the same module unit or in other
translation units of the same named module.
All names declared at namespace scope have module linkage if their declarations are
Linkage (con’t)
attached to a named module, are not exported, and don’t have internal linkage.
(This linkage was created to implement C++20 modules.)
Outline
6 Digit Separators
Digit Separators
• C++14 allows all integer and floating-point literal values to use single quotation marks asdigit separatorsthat areignored bythe C ++
compiler.
• Such separatorsneednot be every three digits —the programmercan choose whereto put them.
• w01/digit-separator.cxx
1 auto d = 42'000'000; // decimal
2 auto o = 042'00'00'00; // octal
3 auto x = 0x9FC2'FACE'CAFE; // hexadecimal
4 auto b = 0b1110'1101'1101'1000'0111'0110; // binary (C++14)
5 auto fp1 = 3.141'592'653'589'793'238'462'643'383'279'50; // floating-point
6 auto fp2 = 2.99'792'458e8; // floating-point, decimal, scientific notation
7 auto fp3 = 0x1FF'0B21p734; // floatiing-point, hexadecimal (C++17)
Outline
The C ++ language defines a number of prefixes and suffixes associated with integer
and floating-point literal values:
Note: C++17 hexadecimal floating-point numbers use a “p” to separate the mantissa and
exponent portions —not an “e”. Such numbers also need not have both mantissa and
exponent values as hexadecimal values.
C ++ Language Literal Prefixes and Suffixes (con’t)
The C ++ language also defines a number of prefixes associated with string literal
values:
w01/raw-string-lit.cxx
1 // NOTE: None of the raw strings below have any escape characters in them.
2 // Everything in the raw string is as-is.
3 char const* s1 = R"(This some as-is text.\nNo newlines here!)";
4 wchar_t const* s2 = LR"(Some more \t\v\n\r as-is text.)";
5 char8_t const* s3 = u8R"nice(Another raw string \x0A\x0D as-is.)nice";
6 char16_t const* s4 = uR"okay(More stuff.)okay";
7 char32_t const* s5 = UR"qwerty(Even more stuff.)qwerty";
C ++ Language Literals
C++11 also allows the integer, floating-point, character, and string literals to produce
objects of user-defined type by using a user-defined suffix.
• C ++ reserves all literal suffixes that do not start with an underscore.
• All user-defined literal suffixes must start with an underscore.
Such suffixes are defined by defining an operator overload of the literal operator, e.g.,
w01/userdef-lit1.cxx
1 struct si_metre { long double value; }; // type representing the SI unit metre
2 si_metre operator""_mm(long double value) { return si_metre{value / 1000.L}; }
3 si_metre operator""_cm(long double value) { return si_metre{value / 100.L}; }
4 si_metre operator""_m(long double value) { return si_metre{value}; }
5 si_metre operator""_km(long double value) { return si_metre{value * 1000.L}; }
6
7 si_metre m1 = 29.5_mm; // 29.5 / 1000 so it is in metres
8 si_metre m2 = 55.321_cm; // 55.321 / 100 so it is in metres
9 si_metre m3 = 22.1234e17_m; // 22.1234e17 metres
10 si_metre m4 = 3156.23e4_km; // 3156.23e4 * 1000 so it is in metres
C ++ Language Literals (con’t)
Additionally:
• operator"" definitions for integer and floating-point literals may be
function templates where the char values in the literal are passed to the
function template
• To process such requires writing advanced “template metaprogramming” code.
• operator"" definitions for string literals are permitted to be function
templates if the function template parameter is a non-type template
parameter of class type
• The string literal is then passed to the constexpr constructor of the
(structural) class type, e.g., see the example on the next slide.
• otherwise operator"" should return the type it is responsible for
constructing.
C ++ Language Literals (con’t)
For those curious about advanced uses of operator"" function templates for string
literals:
w01/userdef-lit2.cxx
1 #include <algorithm> // for std::copy_n
2 #include <cstddef> // for std::size_t
3
4 template <std::size_t N>
5 struct crazy_string_literal_type
6 {
7 char value[N];
8 constexpr crazy_string_literal_type(char const (&str)[N])
9 {
10 std::copy_n(str,N,value);
11 }
12 };
13 template <crazy_string_literal_type c>
14 constexpr auto operator""_hmmm() { return c; }
15
16 auto cool = "This is some text."_hmmm;
C ++ Language Literals (con’t)
C++ defines a number of literal suffixes in the Standard Library that are useful in
programs:
COMP-3400-30-R-2024W Week 1: Introduction, History, and More Paul Preney 104 / 105
References (con’t)