C++语言
模板编程
- C++模板:菜鸟教程
- awesome-cpp
- handbook-Boost1.68.0
- book-C++模板元编程: 概述 Traits和类型操纵 深入探索元函数 整型外覆器和操作 序列与迭代器 算法 视图与地带器适配器 诊断 跨越编译期和运行期边界 领域特定的嵌入式语言 DSEL设计演练
- C++ Template教学指南: 模板基本语法 模板元编程基础 深入理解特化与偏特化
- book-C++设计新思维-泛型编程与设计模式之应用: 第一篇技术 第1章基于Policy的Class设计(Policy-Based Class Design) 第2章技术(Techniques) 第3章Typelist 第4章小型对象分配技术(Small-Object Allocation) 第二篇组件(Component) 第5章泛化仿函数(Generalized Functors) 第6章Singletons(单件)实作技术 第7章Smart Pointers(智能指针) 第8章Object Factory(对象工厂) 第9章Abstract Factory(抽象工厂) 第10章Visitor(访问者,观察者) 第11章MultiMethods 附录一个超迷你的多线程程序库(A Minimalist Multithreading Library)
- book-<深入理解C++11>:
- book-<深入实践C++模板编程>: 模板元编程基础(Hello模板 类亦模板 模板参数类型详解 凡事总有“特例”) 标准库中的模板(容器、迭代器与算法 标准库中的容器 隐形的助手——分配器 标准库中的迭代器 标准库中的算法) 模板编程高级技巧(专用名词——概念 代码膨胀 常用模板编程技巧 元编程) 模板与C++11(右值引用 模板新语法 C++11新特性集锦)
- book-: 导读 全新的C++语言 模板元编程简介 类型特征萃取 实用工具 迭代器 区间 函数对象 指针容器 侵入式容器 多索引容器 流处理 泛型编程 模板元编程 预处理元编程 现代C++开发浅谈
- book-手册:The Boost C++ Libraries.chm: 简介 智能指针 函数对象 事件处理 字符串处理 多线程 异步输入输出 进程间通讯 文件系统 日期与时间 序列化 词法分析器 容器 数据结构 错误处理 类型转换操作符
- book-<现代C++教程-高速上手C++11/14/17/20>
- 中文的C++ Template的教学指南
- 使用 C++ 模板元编程模拟 Lisp
- C++ 模板元编程:一种屠龙之技-知乎
- C++ primer
C++笔记
template <typename T1, typename T2> void doSomthing(T1 x, T2 y){...} 函数模板
template <class T1, class T2> class className{...} //类模板
template <class T, int size> // size is the non-type parameter
现代C++设计新思维
第一篇 技术(Techniques)
第1章 基于Policy的Class设计(Policy-Based Class Design)
第2章 技术(Techniques)
第3章 Typelists
第4章 小型对象分配技术(Small-Object Allocation)
第二篇 组件(Component)
第5章 泛化仿函数(Generalized Functions)
第6章 Singletons(单件)实作技术
第7章 Smart Pointers(智能指针)
第8章 Object Factiories(对象工厂)
第9章 Abstract Factory(抽象工厂)
第10章 Visitor(访问者,视察者)
第11章 Multimethods
附录 一个超迷你的多线程程序库(A Minimalist Multithreading Library)
C++源码摘要
// This is a source version of the cpp cheatsheet available here. Note that this does not compile but may have better
// color-highlight than the markdown version in an editor.
//
// Github version available here: https://github.com/mortennobel/cpp-cheatsheet
// # C++ QUICK REFERENCE / C++ CHEATSHEET
// Based on <a href="http://www.pa.msu.edu/~duxbury/courses/phy480/Cpp_refcard.pdf">Phillip M. Duxbury's C++ Cheatsheet</a> and edited by Morten Nobel-Jørgensen.
// The cheatsheet focus is both on the language as well as common classes from the standard library.
// C++11 additions is inspired by <a href="https://isocpp.org/blog/2012/12/c11-a-cheat-sheet-alex-sinyakov">ISOCPP.org C++11 Cheatsheet</a>).
//
// The goal is to give a concise overview of basic, modern C++ (C++14).
//
// The document is hosted on https://github.com/mortennobel/cpp-cheatsheet. Any comments and feedback are appreciated.
// ## Preprocessor
// Comment to end of line
/* Multi-line comment */
#include <stdio.h> // Insert standard header file
#include "myfile.h" // Insert file in current directory
#define X some text // Replace X with some text
#define F(a,b) a+b // Replace F(1,2) with 1+2
#define X \
some text // Multiline definition
#undef X // Remove definition
#if defined(X) // Conditional compilation (#ifdef X)
#else // Optional (#ifndef X or #if !defined(X))
#endif // Required after #if, #ifdef
// ## Literals
255, 0377, 0xff // Integers (decimal, octal, hex)
2147483647L, 0x7fffffffl // Long (32-bit) integers
123.0, 1.23e2 // double (real) numbers
'a', '\141', '\x61' // Character (literal, octal, hex)
'\n', '\\', '\'', '\"' // Newline, backslash, single quote, double quote
"string\n" // Array of characters ending with newline and \0
"hello" "world" // Concatenated strings
true, false // bool constants 1 and 0
nullptr // Pointer type with the address of 0
// ## Declarations
int x; // Declare x to be an integer (value undefined)
int x=255; // Declare and initialize x to 255
short s; long l; // Usually 16 or 32 bit integer (int may be either)
char c='a'; // Usually 8 bit character
unsigned char u=255;
signed char s=-1; // char might be either
unsigned long x =
0xffffffffL; // short, int, long are signed
float f; double d; // Single or double precision real (never unsigned)
bool b=true; // true or false, may also use int (1 or 0)
int a, b, c; // Multiple declarations
int a[10]; // Array of 10 ints (a[0] through a[9])
int a[]={0,1,2}; // Initialized array (or a[3]={0,1,2}; )
int a[2][2]={{1,2},{4,5}}; // Array of array of ints
char s[]="hello"; // String (6 elements including '\0')
std::string s = "Hello" // Creates string object with value "Hello"
std::string s = R"(Hello
World)"; // Creates string object with value "Hello\nWorld"
int* p; // p is a pointer to (address of) int
char* s="hello"; // s points to unnamed array containing "hello"
void* p=nullptr; // Address of untyped memory (nullptr is 0)
int& r=x; // r is a reference to (alias of) int x
enum weekend {SAT,SUN}; // weekend is a type with values SAT and SUN
enum weekend day; // day is a variable of type weekend
enum weekend{SAT=0,SUN=1}; // Explicit representation as int
enum {SAT,SUN} day; // Anonymous enum
enum class Color {Red,Blue};// Color is a strict type with values Red and Blue
Color x = Color::Red; // Assign Color x to red
typedef String char*; // String s; means char* s;
const int c=3; // Constants must be initialized, cannot assign to
const int* p=a; // Contents of p (elements of a) are constant
int* const p=a; // p (but not contents) are constant
const int* const p=a; // Both p and its contents are constant
const int& cr=x; // cr cannot be assigned to change x
int8_t,uint8_t,int16_t,
uint16_t,int32_t,uint32_t,
int64_t,uint64_t // Fixed length standard types
auto it = m.begin(); // Declares it to the result of m.begin()
auto const param = config["param"];
// Declares it to the const result
auto& s = singleton::instance();
// Declares it to a reference of the result
// ## STORAGE Classes
int x; // Auto (memory exists only while in scope)
static int x; // Global lifetime even if local scope
extern int x; // Information only, declared elsewhere
// ## Statements
x=y; // Every expression is a statement
int x; // Declarations are statements
; // Empty statement
{ // A block is a single statement
int x; // Scope of x is from declaration to end of block
}
if (x) a; // If x is true (not 0), evaluate a
else if (y) b; // If not x and y (optional, may be repeated)
else c; // If not x and not y (optional)
while (x) a; // Repeat 0 or more times while x is true
for (x; y; z) a; // Equivalent to: x; while(y) {a; z;}
for (x : y) a; // Range-based for loop e.g.
// for (auto& x in someList) x.y();
do a; while (x); // Equivalent to: a; while(x) a;
switch (x) { // x must be int
case X1: a; // If x == X1 (must be a const), jump here
case X2: b; // Else if x == X2, jump here
default: c; // Else jump here (optional)
}
break; // Jump out of while, do, or for loop, or switch
continue; // Jump to bottom of while, do, or for loop
return x; // Return x from function to caller
try { a; }
catch (T t) { b; } // If a throws a T, then jump here
catch (...) { c; } // If a throws something else, jump here
// ## Functions
int f(int x, int y); // f is a function taking 2 ints and returning int
void f(); // f is a procedure taking no arguments
void f(int a=0); // f() is equivalent to f(0)
f(); // Default return type is int
inline f(); // Optimize for speed
f() { statements; } // Function definition (must be global)
T operator+(T x, T y); // a+b (if type T) calls operator+(a, b)
T operator-(T x); // -a calls function operator-(a)
T operator++(int); // postfix ++ or -- (parameter ignored)
extern "C" {void f();} // f() was compiled in C
// Function parameters and return values may be of any type. A function must either be declared or defined before
// it is used. It may be declared first and defined later. Every program consists of a set of a set of global variable
// declarations and a set of function definitions (possibly in separate files), one of which must be:
int main() { statements... } // or
int main(int argc, char* argv[]) { statements... }
// `argv` is an array of `argc` strings from the command line.
// By convention, `main` returns status `0` if successful, `1` or higher for errors.
//
// Functions with different parameters may have the same name (overloading). Operators except `::` `.` `.*` `?:` may be overloaded.
// Precedence order is not affected. New operators may not be created.
// ## Expressions
// Operators are grouped by precedence, highest first. Unary operators and assignment evaluate right to left. All
// others are left to right. Precedence does not affect order of evaluation, which is undefined. There are no run time
// checks for arrays out of bounds, invalid pointers, etc.
T::X // Name X defined in class T
N::X // Name X defined in namespace N
::X // Global name X
t.x // Member x of struct or class t
p-> x // Member x of struct or class pointed to by p
a[i] // i'th element of array a
f(x,y) // Call to function f with arguments x and y
T(x,y) // Object of class T initialized with x and y
x++ // Add 1 to x, evaluates to original x (postfix)
x-- // Subtract 1 from x, evaluates to original x
typeid(x) // Type of x
typeid(T) // Equals typeid(x) if x is a T
dynamic_cast< T>(x) // Converts x to a T, checked at run time.
static_cast< T>(x) // Converts x to a T, not checked
reinterpret_cast< T>(x) // Interpret bits of x as a T
const_cast< T>(x) // Converts x to same type T but not const
sizeof x // Number of bytes used to represent object x
sizeof(T) // Number of bytes to represent type T
++x // Add 1 to x, evaluates to new value (prefix)
--x // Subtract 1 from x, evaluates to new value
~x // Bitwise complement of x
!x // true if x is 0, else false (1 or 0 in C)
-x // Unary minus
+x // Unary plus (default)
&x // Address of x
*p // Contents of address p (*&x equals x)
new T // Address of newly allocated T object
new T(x, y) // Address of a T initialized with x, y
new T[x] // Address of allocated n-element array of T
delete p // Destroy and free object at address p
delete[] p // Destroy and free array of objects at p
(T) x // Convert x to T (obsolete, use .._cast<T>(x))
x * y // Multiply
x / y // Divide (integers round toward 0)
x % y // Modulo (result has sign of x)
x + y // Add, or \&x[y]
x - y // Subtract, or number of elements from *x to *y
x << y // x shifted y bits to left (x * pow(2, y))
x >> y // x shifted y bits to right (x / pow(2, y))
x < y // Less than
x <= y // Less than or equal to
x > y // Greater than
x >= y // Greater than or equal to
x & y // Bitwise and (3 & 6 is 2)
x ^ y // Bitwise exclusive or (3 ^ 6 is 5)
x | y // Bitwise or (3 | 6 is 7)
x && y // x and then y (evaluates y only if x (not 0))
x || y // x or else y (evaluates y only if x is false (0))
x = y // Assign y to x, returns new value of x
x += y // x = x + y, also -= *= /= <<= >>= &= |= ^=
x ? y : z // y if x is true (nonzero), else z
throw x // Throw exception, aborts if not caught
x , y // evaluates x and y, returns y (seldom used)
// ## Classes
class T { // A new type
private: // Section accessible only to T's member functions
protected: // Also accessible to classes derived from T
public: // Accessible to all
int x; // Member data
void f(); // Member function
void g() {return;} // Inline member function
void h() const; // Does not modify any data members
int operator+(int y); // t+y means t.operator+(y)
int operator-(); // -t means t.operator-()
T(): x(1) {} // Constructor with initialization list
T(const T& t): x(t.x) {}// Copy constructor
T& operator=(const T& t)
{x=t.x; return *this; } // Assignment operator
~T(); // Destructor (automatic cleanup routine)
explicit T(int a); // Allow t=T(3) but not t=3
T(float x): T((int)x) {}// Delegate constructor to T(int)
operator int() const
{return x;} // Allows int(t)
friend void i(); // Global function i() has private access
friend class U; // Members of class U have private access
static int y; // Data shared by all T objects
static void l(); // Shared code. May access y but not x
class Z {}; // Nested class T::Z
typedef int V; // T::V means int
};
void T::f() { // Code for member function f of class T
this->x = x;} // this is address of self (means x=x;)
int T::y = 2; // Initialization of static member (required)
T::l(); // Call to static member
T t; // Create object t implicit call constructor
t.f(); // Call method f on object t
struct T { // Equivalent to: class T { public:
virtual void i(); // May be overridden at run time by derived class
virtual void g()=0; }; // Must be overridden (pure virtual)
class U: public T { // Derived class U inherits all members of base T
public:
void g(int) override; }; // Override method g
class V: private T {}; // Inherited members of T become private
class W: public T, public U {};
// Multiple inheritance
class X: public virtual T {};
// Classes derived from X have base T directly
// All classes have a default copy constructor, assignment operator, and destructor, which perform the
// corresponding operations on each data member and each base class as shown above. There is also a default no-argument
// constructor (required to create arrays) if the class has no constructors. Constructors, assignment, and
// destructors do not inherit.
// ## Templates
template <class T> T f(T t);// Overload f for all types
template <class T> class X {// Class with type parameter T
X(T t); }; // A constructor
template <class T> X<T>::X(T t) {}
// Definition of constructor
X<int> x(3); // An object of type "X of int"
template <class T, class U=T, int n=0>
// Template with default parameters
// ## Namespaces
namespace N {class T {};} // Hide name T
N::T t; // Use name T in namespace N
using namespace N; // Make T visible without N::
// ## `memory` (dynamic memory management)
#include <memory> // Include memory (std namespace)
shared_ptr<int> x; // Empty shared_ptr to a integer on heap. Uses reference counting for cleaning up objects.
x = make_shared<int>(12); // Allocate value 12 on heap
shared_ptr<int> y = x; // Copy shared_ptr, implicit changes reference count to 2.
cout << *y; // Dereference y to print '12'
if (y.get() == x.get()) { // Raw pointers (here x == y)
cout << "Same";
}
y.reset(); // Eliminate one owner of object
if (y.get() != x.get()) {
cout << "Different";
}
if (y == nullptr) { // Can compare against nullptr (here returns true)
cout << "Empty";
}
y = make_shared<int>(15); // Assign new value
cout << *y; // Dereference x to print '15'
cout << *x; // Dereference x to print '12'
weak_ptr<int> w; // Create empty weak pointer
w = y; // w has weak reference to y.
if (shared_ptr<int> s = w.lock()) { // Has to be copied into a shared_ptr before usage
cout << *s;
}
unique_ptr<int> z; // Create empty unique pointers
unique_ptr<int> q;
z = make_unique<int>(16); // Allocate int (16) on heap. Only one reference allowed.
q = move(z); // Move reference from z to q.
if (z == nullptr){
cout << "Z null";
}
cout << *q;
shared_ptr<B> r;
r = dynamic_pointer_cast<B>(t); // Converts t to a shared_ptr<B>
// ## `math.h`, `cmath` (floating point math)
#include <cmath> // Include cmath (std namespace)
sin(x); cos(x); tan(x); // Trig functions, x (double) is in radians
asin(x); acos(x); atan(x); // Inverses
atan2(y, x); // atan(y/x)
sinh(x); cosh(x); tanh(x); // Hyperbolic sin, cos, tan functions
exp(x); log(x); log10(x); // e to the x, log base e, log base 10
pow(x, y); sqrt(x); // x to the y, square root
ceil(x); floor(x); // Round up or down (as a double)
fabs(x); fmod(x, y); // Absolute value, x mod y
// ## `assert.h`, `cassert` (Debugging Aid)
#include <cassert> // Include iostream (std namespace)
assert(e); // If e is false, print message and abort
#define NDEBUG // (before #include <assert.h>), turn off assert
// ## `iostream.h`, `iostream` (Replaces `stdio.h`)
#include <iostream> // Include iostream (std namespace)
cin >> x >> y; // Read words x and y (any type) from stdin
cout << "x=" << 3 << endl; // Write line to stdout
cerr << x << y << flush; // Write to stderr and flush
c = cin.get(); // c = getchar();
cin.get(c); // Read char
cin.getline(s, n, '\n'); // Read line into char s[n] to '\n' (default)
if (cin) // Good state (not EOF)?
// To read/write any type T:
istream& operator>>(istream& i, T& x) {i >> ...; x=...; return i;}
ostream& operator<<(ostream& o, const T& x) {return o << ...;}
// ## `fstream.h`, `fstream` (File I/O works like `cin`, `cout` as above)
#include <fstream> // Include filestream (std namespace)
ifstream f1("filename"); // Open text file for reading
if (f1) // Test if open and input available
f1 >> x; // Read object from file
f1.get(s); // Read char or line
f1.getline(s, n); // Read line into string s[n]
ofstream f2("filename"); // Open file for writing
if (f2) f2 << x; // Write to file
// ## `string` (Variable sized character array)
#include <string> // Include string (std namespace)
string s1, s2="hello"; // Create strings
s1.size(), s2.size(); // Number of characters: 0, 5
s1 += s2 + ' ' + "world"; // Concatenation
s1 == "hello world" // Comparison, also <, >, !=, etc.
s1[0]; // 'h'
s1.substr(m, n); // Substring of size n starting at s1[m]
s1.c_str(); // Convert to const char*
s1 = to_string(12.05); // Converts number to string
getline(cin, s); // Read line ending in '\n'
// ## `vector` (Variable sized array/stack with built in memory allocation)
#include <vector> // Include vector (std namespace)
vector<int> a(10); // a[0]..a[9] are int (default size is 0)
vector<int> b{1,2,3}; // Create vector with values 1,2,3
a.size(); // Number of elements (10)
a.push_back(3); // Increase size to 11, a[10]=3
a.back()=4; // a[10]=4;
a.pop_back(); // Decrease size by 1
a.front(); // a[0];
a[20]=1; // Crash: not bounds checked
a.at(20)=1; // Like a[20] but throws out_of_range()
for (int& p : a)
p=0; // C++11: Set all elements of a to 0
for (vector<int>::iterator p=a.begin(); p!=a.end(); ++p)
*p=0; // C++03: Set all elements of a to 0
vector<int> b(a.begin(), a.end()); // b is copy of a
vector<T> c(n, x); // c[0]..c[n-1] init to x
T d[10]; vector<T> e(d, d+10); // e is initialized from d
// ## `deque` (Array stack queue)
// `deque<T>` is like `vector<T>`, but also supports:
#include <deque> // Include deque (std namespace)
a.push_front(x); // Puts x at a[0], shifts elements toward back
a.pop_front(); // Removes a[0], shifts toward front
// ## `utility` (pair)
#include <utility> // Include utility (std namespace)
pair<string, int> a("hello", 3); // A 2-element struct
a.first; // "hello"
a.second; // 3
// ## `map` (associative array - usually implemented as binary search trees - avg. time complexity: O(log n))
#include <map> // Include map (std namespace)
map<string, int> a; // Map from string to int
a["hello"] = 3; // Add or replace element a["hello"]
for (auto& p:a)
cout << p.first << p.second; // Prints hello, 3
a.size(); // 1
// ## `unordered_map` (associative array - usually implemented as hash table - avg. time complexity: O(1))
#include <unordered_map> // Include map (std namespace)
unordered_map<string, int> a; // Map from string to int
a["hello"] = 3; // Add or replace element a["hello"]
for (auto& p:a)
cout << p.first << p.second; // Prints hello, 3
a.size(); // 1
// ## `set` (store unique elements - usually implemented as binary search trees - avg. time complexity: O(log n))
#include <set> // Include set (std namespace)
set<int> s; // Set of integers
s.insert(123); // Add element to set
if (s.find(123) != s.end()) // Search for an element
s.erase(123);
cout << s.size(); // Number of elements in set
// ## `unordered_set` (store unique elements - usually implemented as a hash set - avg. time complexity: O(1))
#include <unordered_set> // Include set (std namespace)
unordered_set<int> s; // Set of integers
s.insert(123); // Add element to set
if (s.find(123) != s.end()) // Search for an element
s.erase(123);
cout << s.size(); // Number of elements in set
// ## `algorithm` (A collection of 60 algorithms on sequences with iterators)
#include <algorithm> // Include algorithm (std namespace)
min(x, y); max(x, y); // Smaller/larger of x, y (any type defining <)
swap(x, y); // Exchange values of variables x and y
sort(a, a+n); // Sort array a[0]..a[n-1] by <
sort(a.begin(), a.end()); // Sort vector or deque
reverse(a.begin(), a.end()); // Reverse vector or deque
// ## `chrono` (Time related library)
#include <chrono> // Include chrono
using namespace std::chrono; // Use namespace
auto from = // Get current time_point
high_resolution_clock::now();
// ... do some work
auto to = // Get current time_point
high_resolution_clock::now();
using ms = // Define ms as floating point duration
duration<float, milliseconds::period>;
// Compute duration in milliseconds
cout << duration_cast<ms>(to - from)
.count() << "ms";
// ## `thread` (Multi-threading library)
#include <thread> // Include thread
unsigned c =
hardware_concurrency(); // Hardware threads (or 0 for unknown)
auto lambdaFn = [](){ // Lambda function used for thread body
cout << "Hello multithreading";
};
thread t(lambdaFn); // Create and run thread with lambda
t.join(); // Wait for t finishes
// --- shared resource example ---
mutex mut; // Mutex for synchronization
condition_variable cond; // Shared condition variable
const char* sharedMes // Shared resource
= nullptr;
auto pingPongFn = // thread body (lambda). Print someone else's message
[&](const char* mes){
while (true){
unique_lock<mutex> lock(mut);// locks the mutex
do {
cond.wait(lock, [&](){ // wait for condition to be true (unlocks while waiting which allows other threads to modify)
return sharedMes != mes; // statement for when to continue
});
} while (sharedMes == mes); // prevents spurious wakeup
cout << sharedMes << endl;
sharedMes = mes;
lock.unlock(); // no need to have lock on notify
cond.notify_all(); // notify all condition has changed
}
};
sharedMes = "ping";
thread t1(pingPongFn, sharedMes); // start example with 3 concurrent threads
thread t2(pingPongFn, "pong");
thread t3(pingPongFn, "boing");
// ## `future` (thread support library)
#include <future> // Include future
function<int(int)> fib = // Create lambda function
[&](int i){
if (i <= 1){
return 1;
}
return fib(i-1)
+ fib(i-2);
};
future<int> fut = // result of async function
async(launch::async, fib, 4); // start async function in other thread
// do some other work
cout << fut.get(); // get result of async function. Wait if needed.
cpp_cheatsheet
INDEX
- Variable and fundamental data types
- Console Input/Output
- Generating Random Numbers
- Advanced Data Types
- Dynamic Memory Allocation
- Reference Variables
- For Each Loop
- Functions
- Object Oriented Programming
- Operator Overloading
- Object Relationship
- Inheritance
- Virtual Functions
- Templates
Variable and fundamental data types
Initializing a variable
- Copy initialization:
int numRings = 20;
- Direct initialization:
int numRings(20);
- Uniform initialization:
int numRings{20}
If uniform initialization is used with no value. Default is 0.
int numRings{}
Integers
Fixed width integers
Will give fixed sized integer in all architecture.
#include <cstdint> // for fixed width integers
/*
* 8 bit singed integer. Many systems consider them as chars. So it is better
* to not use them if using integers is the purpose
*/
int8_t var;
uint8_t var; // 8 bit unsigned integer
intN_t var; // N = 16, 32, 64 bits signed integer
uintN_t var; // N = 16, 32, 64 bits unsigned integer
Fixed width integers performance is machine dependent. To get the fastest
integer type on a specific machine use int_fastN_t
. It will give the fastest
integer which is at least N bits long. N = 8, 16, 32, 64.
int_fast32_t var;
To get the smallest integer which is at least N bits long use int_leastN_t
where N = 8, 16, 32, 64.
int_least64_t var;
Floating point numbers
Setting precision of a floating point number:
#include <iostream>
#include <iomanip> // for std::setprecision()
int main(){
double d{12.34567890};
std::cout << "Without precision: " << d << std::endl;
std::cout << std::setprecision(4);
std::cout << "With precision: " << d << std::endl;
return 0;
}
Special floating numbers: positive infinity, negative infinity, not a number.
#include <iostream>
int main(){
float zero(0.0);
float posinf = 5.0 / zero;
float neginf = -5.0 / zero;
float nan = zero / zero;
std::cout << posinf << std::endl;
std::cout << neginf << std::endl;
std::cout << nan << std::endl;
return 0;
}
Boolean Numbers
#include <iostream>
int main(){
bool universeCameFromNothing(true);
std::cout << "Universe came from nothing: " << universeCameFromNothing
<< std::endl;
std::cout << std::boolalpha;
std::cout << "Universe came from nothing: " << universeCameFromNothing
<< std::endl;
return 0;
}
Type Casting
#include <iostream>
int main(){
char ch(65);
std::cout << ch << std::endl;
std::cout << static_cast<int>(ch) << std::endl;
return 0;
}
To get the variable or expression type.
#include <typeinfo>
int main(){
int numerator(50);
double denominator(5.0);
std::cout << typeid(numerator).name() << std::endl;
std::cout << typeid(numerator / denominator).name() << std::endl;
}
Literal
int integer(50); // integer
float f(0.05f); // used f suffix as default literal is double type
double d(0.31416); // double floating literal
int hex(0xa0); // hexadecimal literal
int oct(012); // Octal literal
int bin(0b1010); // Binary literal
int longNumber(1'23'570) // c++14 only
Constants
const double avg(6.023e23);
const double massEarth; // This is not allowed
int x(50);
const int y(x) // This is allowed
constexpr double adg(9.8); // Compile time constant. Value of the constant
// must be resolved in compile time otherwise
// will generate an error. This is c++11 feature
Variable Scopes and duration
shadowing:
int number(5);
if(number == 5){
int number; // local variable
number = 10; // will effect only local variable
// this is shadowing
std::cout << number << std::endl; // will print local
}
std::cout << number << std::endl; // will print outer block number
Global scope operator
::
is the global scope operator.
int x(50); // global variable
int main(){
int x(40);
std::cout << x << std::endl; // will print local x
std::cout << ::x << std::endl; // will print global x
}
Internal Variable: Can be used anywhere in the file they are defined but not
out of the file.
External Variable: Cab be used across multiple files. Global variables are
by default external. static keyword can be used to make them internal.
Console Input/Output
Console I/O Methods
std::cin
is used for console input.std::cin
takes inputs untill first
whitespace.
#include <iostream>
int main(){
int selection;
std::cin >> selection;
std::cout << "You have selected: " << selection << std::endl;
return 0;
}
std::getline()
is used to take whole line as input.
#include <iostream>
#include <string>
int main(){
std::string name;
std::cout << "Enter Name: ";
std::getline(std::cin, name);
std::cout << "Your name is: " << name;
return 0;
}
Error Handling in Console Input
std::cin
takes upto newline from the input stream. So it will be a problem if any other input function is used after taking numeric input from std::cin.
#include <iostream>
#include <string>
int main(){
std::string name;
int select;
std::cout << "Select: ";
std::cin >> select;
std::cout << "Enter name: ";
std::getline(std::cin, name); // will not work
std::cout << "Your name is: " << name << "! You have selected: "
<< select;
return 0;
}
To solve this problem std::cin.ignore(n, ch)
can be used where n is the
number of character to ignore from the input stream before ch character is
found.
#include <iostream>
#include <string>
int main(){
int select;
std::string name;
std::cout << "Select: ";
std::cin >> select;
std::cin.ignore(32767, '\n');
std::cout << "Enter name: ";
std::getline(std::cin, name);
std::cout << "Hi " << name << "! You have selected " << select << std::endl;
return 0;
}
A Program Handling All the Error Case in Input
Expand to see code
#include <iostream>
double getDouble(){
double d;
while(true){
std::cout << "Enter: ";
std::cin >> d;
std::cin.ignore(32767, '\n'); /* clear '\n' from input stream */
/*
* Input will fail if a valid number isn't typed.
* if input fails, cin will set fail flag and stop extracting
* characters from input stream.
*/
if(std::cin.fail()){
std::cout << "Please enter a floating number" << std::endl;
std::cin.clear(); /* Clear fail flag */
std::cin.ignore(32767, '\n'); /* Clear input stream */
}
else{
return d;
}
}
}
char getOperator(){
char op;
while(true){
std::cout << "Enter (+, -, * or /): ";
std::cin >> op;
std::cin.ignore(32767, '\n');
if(op == '+' || op == '-' || op == '*' || op == '/'){
return op;
}
else{
std::cout << "Bad operator. Input again." << std::endl;
}
}
}
void printResult(double d1, char op, double d2){
if(op == '+'){
std::cout << d1 << " + " << d2 << " = " << d1 + d2 << std::endl;
}
else if(op == '-'){
std::cout << d1 << " - " << d2 << " = " << d1 - d2 << std::endl;
}
else if(op == '*'){
std::cout << d1 << " * " << d2 << " = " << d1 * d2 << std::endl;
}
else{
if(d2 != 0){
std::cout << d1 << " / " << d2 << " = " << d1 / d2 << std::endl;
}
else{
std::cout << "Can't devide by zero!";
}
}
}
int main(){
double d1 = getDouble();
char op = getOperator();
double d2 = getDouble();
printResult(d1, op, d2);
return 0;
}
Generating Random Numbers
Generating Random Numbers
#include <iostream>
#include <ctime>
#include <cstdlib>
int main(){
/* For generating different seed each time the program runs */
srand(static_cast<unsigned int>(time(0)));
std::cout << rand();
return 0;
}
Function for generating Random Numbers Between A Range
Using modulus:
#include <iostream>
#include <ctime>
#include <cstdlib>
int getRandom(int min, int max){
return min + (rand() % (max - min + 1));
}
int main(){
/* For generating different seed each time the program runs */
srand(static_cast<unsigned int>(time(0)));
std::cout << getRandom(1, 6);
return 0;
}
But this method is biased to low numbers. Following method has less bias to
low numbers.
#include <iostream>
#include <ctime>
#include <cstdlib>
int getRandom(int min, int max){
static const double fraction = 1.0 / RAND_MAX;
return min + ((max - min + 1) * (rand() * fraction));
}
int main(){
/* For generating different seed each time the program runs */
srand(static_cast<unsigned int>(time(0)));
std::cout << getRandom(1, 6);
return 0;
}
For details: http://www.learncpp.com/cpp-tutorial/59-random-number-generation/
Advanced Data Types
Array
Array Indexes
Array index must be a compile time constant.
#include <iostream>
int main(){
int array[5]; // ok
#define ARR_SIZE 5
int array[ARR_SIZE]; // ok
int const arr_size = 5;
int array[arr_size]; // ok
int arr_size = 5;
}
Representing Array Indexes with Enumerators
Array index can be represented with enumerators. In this way it makes
arrays well documented:
#include <iostream>
namespace Store{
enum Store{
LM7805,
MAX485,
LM311,
ATMEGA64,
LED,
MAX_ELEMENT
};
}
int main(){
int inStore[Store::MAX_ELEMENT];
inStore[Store::LM7805] = 50;
std::cout << "There are " << inStore[Store::LM7805] \
<< " LM7805 in store" << std::endl;
return 0;
}
Relation Between Array and Pointer
Arrays are actually pointers. It points to the first element of the array.
#include <iostream>
int main(){
int arr[2] = {1, 2};
/* Following two address will be same*/
std::cout << arr << std::endl;
std::cout << &arr[0] << std::endl;
return 0;
}
Difference Between Array and Pointer to Array
The type of the array is int (*)[n]
if it is an integer array
but the type of the pointer to that array is int *
. Array type contains
the size information of the array. When array is dereferenced or assigned
to a pointer it implicitly converts itself into type *
fromtype (*)[n]
so size information is lost. Here is an example of this
behaviour:
#include <iostream>
int main(){
int arr[5] = {1, 2, 3, 4, 5};
int *arrPtr = arr; // arr is converted from int (*)[2] to int *
/* Will print the size of the array which is 5 * 8 bytes */
std::cout << sizeof(arr) << std::endl;
/* Will print the size of the pointer which is 8 bytes */
std::cout << sizeof(arrPtr) << std::endl;
return 0;
}
String Constants Using Fixed Sized Array and Pointer
#include <iostream>
int main(){
/*
* keep the string constant in memory with r/w access
* and return the pointer to it.
* So string constant can be changed any time later
*/
char arr[] = "hello, world";
/*
* Keep the string constant in read-only section of memory
* so it can't be changed
*/
char *text = "GNU is not Unix";
/* As it is a constant so its better to initialize following way */
const char *text = "GNU is not Unix";
arr[0] = 'g'; // This OK
/*
* In this case as string constant is kept in read-only
* memory, doing this will generate segmentation
* fault
*/
*(text + 2) = 'O';
std::cout << arr << std::endl;
std::cout << text << std::endl;
return 0;
}
Pointers
Definig NULL Pointer C++ Way
From C++11 nullptr
keyword can be used to define a NULL pointer.
#include <iostream>
int main(){
int *ptr = nullptr;
if(ptr){
std::cout << "Not null" << std::endl;
}
else{
std::cout << "Null" << std::endl;
}
return 0;
}
Void Pointers
- Can point to any data type
- Have to cast manually to a data type before dereferencing.
- Pointer arithmetic can’t be done using void pointers as size of the
obect isn’t known
#include <iostream>
int main(){
int x(5);
void *ptr = &x; // pointing to an integer
std::cout << *static_cast<int*>(ptr) << std::endl;
char ch = 'P'; // pointing to a char
ptr = &ch;
std::cout << static_cast<char*>(ptr) << std::endl;
return 0;
}
Converting A Pointer Address to Integer
Using reinterpret_cast<>
:
#include <iostream>
int main(){
int x = 17;
unsigned int addressX = reinterpret_cast<int>(&x);
std::cout << addressX << std::endl;
return 0;
}
Dynamic Memory Allocation
There are three basic type of memory allocation:
- Static memory allocation: Static and global variables. Allocated
when program runs. Persist throught the program life. Memory is taken from the stack. - Atomatic memory allocation: Function parameter and local variables. Allocated when enter into relevent block and deallocated when exited the block. Memory is taken from the stack.
- Dynamic memory allocation: Memory allocated and deallocated dynamically. Memory is taken from the heap.
Allocating Memory dynamically
Dynamically memory is allocated using the new
keyword.
#include <iostream>
int main(){
int *ptr = new int; // dynamically an integer is allocated.
*ptr = 5;
return 0;
}
Deallocating memory
Memory is deallocated using the delete
keyword.
#include <iostream>
int main(){
int *ptr = new int(5); // memory is allocated to the pointer
/* memory is deallocated.
* memory is realesed by os.
*/
delete ptr;
/* still the pointer is holding the memory address
* so its better to make it null
*/
ptr = 0;
ptr = nullptr; // c++11
return 0;
}
Memory leak
memory leak happens when allocated memory can’t be deallocated.
#include <iostream>
void doSomthing(){
/* Memory is allocated but not deallocated
* so memory leak happens when the variable
* goes out of scope as there is no way
* to deallocate in that case
*/
int *ptr = new int;
}
int main(){
doSomthing();
return 0;
}
#include <iostream>
int main(){
int *ptr = int new;
int val;
// assigning to a address with out deallocating
ptr = &val; // memory leak
return 0;
}
#include <iostream>
int main(){
int *ptr = new int(5);
// allocating new memory without deallocating previous one
int *ptr = new int(10);
return 0;
}
Reference Variables
Create alias for a variable. Basically share same memory address. Must be
initialized with an addressable object. Can be used in function to pass
parameter by reference.
#include <iostream>
int main(){
int x(10);
int &y = x; // reference variable
/*
* will output:
* 10
* 10
*/
std::cout << x << std::endl
std::cout << y << std::endl
return 0;
}
For Each Loop
- Only works from c++11 above
- Can’t be used in case of decayed arrays and dynamically allocated arrays.
#include <iostream>
int main(){
int fibseq[] = {1, 1, 2, 3, 5, 8, 13, 21};
std::cout << "Fibonacci Sequence: ";
for(const auto &elem: fibseq){
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
Functions
Function Pointers
#include <iostream>
int foo(int x){
return x*x;
}
int main(){
int (*square)(int) = foo;
std::cout << square(10) << std::endl;
return 0;
}
- Can’t be used for function’s with default arguments
Function Ellipsis
Ellipsis can be used to pass variable length argument in a function.
#include <iostream>
#include <cstdarg> // to use ellipsis
void printNum(int count, ...){
va_list list;
va_start(list, count);
for(int arg = 0; arg < count; arg++){
std::cout << va_arg(list, int) << std::endl;
}
va_end(list);
}
int main(){
printNum(5, 1, 2, 3, 4, 5);
return 0;
}
- Ellipsis are dangerous. Try to avoid them. For more – http://www.learncpp.com/cpp-tutorial/714-ellipsis-and-why-to-avoid-them/
Lambda Functions
To create anonymous functions. Simple example:
#include <iostream>
#include <algorithm>
#include <vector>
int main(int argc, char *argv[]) {
std::vector<bool> bitvect{1, 0, 0, 1};
/* lambda function example: used to make ~bitvect */
std::transform(bitvect.begin(), bitvect.end(), bitvect.begin(),
[](bool b){ return b == 1 ? 0 : 1; });
return 0;
}
Syntaxt:
[&](){}
: Capture all outside variable by reference.[=](){}
: Capture all outside variable by value.[&x](){}
: Capture only outside variable x
by reference.[x](){}
: Capture only outside variable x
by value.[&, x](){}
: Capture all outside variable by reference but x
by value.[]() -> Type {}
: To specify return type.
Object Oriented Programming
Basic Class Example
#include <iostream>
class Point{
private:
double m_x;
double m_y;
public:
double getX(){
return m_x;
}
void setX(double x){
m_x = x;
}
double getY(){
return m_y;
}
void setY(double y){
m_y = y;
}
};
int main(){
Point p;
p.setX(-2.5);
p.setY(2.5);
std::cout << "(" << p.getX() << ", " << p.getY() << ")" << std::endl;
return 0;
}
Constructors
#include <iostream>
class Point{
private:
double m_x;
double m_y;
public:
Point(double x = 0, double y = 0): m_x(x), m_y(y){
// empty
}
double getX(){
return m_x;
}
void setX(double x){
m_x = x;
}
double getY(){
return m_y;
}
void setY(double y){
m_y = y;
}
void printPoint(){
std::cout << "(" << m_x << ", " << m_y << ")" << std::endl;
}
};
int main(){
Point p(0.5, 0.5);
p.printPoint();
return 0;
}
In c++11 its possible to give default value in class memeber variable
declaration.
#include <iostream>
class Point{
private:
double m_x = 0; // default value of x
double m_y = 0; // default value of y
public:
// member variable will be initialized with default value
// if called
Point(){
//empty
}
double getX(){
return m_x;
}
void setX(double x){
m_x = x;
}
double getY(){
return m_y;
}
void setY(double y){
m_y = y;
}
void printPoint(){
std::cout << "(" << m_x << ", " << m_y << ")" << std::endl;
}
};
int main(){
Point p; // will call default constructor
p.printPoint();
return 0;
}
Destructors
#include <iostream>
#include <cassert>
class Point{
private:
double m_x;
double m_y;
public:
Point(double x = 0, double y = 0): m_x(x), m_y(y){
//empty
}
double getX(){
return m_x;
}
void setX(double x){
m_x = x;
}
double getY(){
return m_y;
}
void setY(double y){
m_y = y;
}
void printPoint(){
std::cout << "(" << m_x << ", " << m_y << ")" << std::endl;
}
};
class PointArray{
private:
Point *m_points;
int m_length;
public:
PointArray(int length){
m_points = new Point[length];
m_length = length;
}
// Destructor
~PointArray(){
delete[] m_points;
}
void insert(Point &p, int index){
assert(index >= 0 && index < m_length);
m_points[index] = p;
}
Point& get(int index){
assert(index >= 0 && index < m_length);
return m_points[index];
}
};
int main(){
PointArray parr(5);
Point p(2, 3);
Point q;
parr.insert(p, 0);
q = parr.get(0);
q.printPoint();
return 0;
}
Static Member Variables
- Will shared by all object.
- Not bound to any object. Bound to the whole class. So it is possible
to use this variable without any object.
#include <iostream>
class Static{
public:
static int id;
};
/* Have to initialize first otherwise linker error will generate */
int Static::id = 1;
int main(){
Static s;
Static t;
/* Shared by both object */
s.id = 5;
std::cout << s.id << "\t" << t.id << std::endl;
/* Bound to whole class */
Static::id = 10;
std::cout << s.id << "\t" << t.id << std::endl;
return 0;
}
Static Member Functions
- Not bound to any object.
#include <iostream>
class ID{
private:
static int m_id;
public:
static int getID(){
return m_id;
}
};
/* Have to initialize first otherwise linker error will generate */
int ID::m_id = 1;
int main(){
std::cout << ID::getID << std::endl;
return 0;
}
Member Types
In C++ classes can have memeber types or nested types. They make the class
easy to maintain. For example in the following example it will be easy
to change the type from int to double. It need to change in only one line.
#include <iostream>
class Point{
public:
using point_t = int; // Member type
Point(point_t x, point_t y): m_x(x), m_y(y){}
void print(void){
std::cout << "(" << m_x << ", " << m_y << ")";
}
private:
point_t m_x;
point_t m_y;
};
int main(int argc, char *argv[]){
Point p(10, 20);
p.print();
return 0;
}
Access Specifiers
public:
private:
protected:
Chaining member functions
#include <iostream>
class Point{
public:
using point_t = int;
Point(point_t x, point_t y): m_x(x), m_y(y){}
Point& add(point_t x, point_t y){
this->m_x += x;
this->m_y += y;
return *this;
}
Point& mul(point_t x, point_t y){
this->m_x *= x;
this->m_y *= y;
return *this;
}
void print(void){
std::cout << "(" << m_x << ", " << m_y << ")";
}
private:
point_t m_x;
point_t m_y;
};
int main(int argc, char *argv[]){
Point p(10, 20);
p.add(3, 5).mul(7, 8).add(2, 3);
p.print();
return 0;
}
Difference between structs and classes in C++
C++ structs and classes are same. Only difference is that all members in structs are public.
Friend function and friend class
Friend functions and classes can access the private members of a class. In the following example printWeather()
is friend of both Humidity
and Temperature
class. So it can access
private members of both classes.
#include <iostream>
class Humidity;
class Temperature
{
private:
int m_temp;
public:
Temperature(int temp=0) { m_temp = temp; }
friend void printWeather(const Temperature &temperature, const Humidity &humidity);
};
class Humidity
{
private:
int m_humidity;
public:
Humidity(int humidity=0) { m_humidity = humidity; }
friend void printWeather(const Temperature &temperature, const Humidity &humidity);
};
void printWeather(const Temperature &temperature, const Humidity &humidity)
{
std::cout << "The temperature is " << temperature.m_temp <<
" and the humidity is " << humidity.m_humidity << '\n';
}
int main()
{
Humidity hum(10);
Temperature temp(12);
printWeather(temp, hum);
return 0;
}
Classes can also be friend of another class. In following example Display
class if a friend
of Storage
class so it can access the private members.
#include <iostream>
class Storage
{
private:
int m_nValue;
double m_dValue;
public:
Storage(int nValue, double dValue)
{
m_nValue = nValue;
m_dValue = dValue;
}
// Make the Display class a friend of Storage
friend class Display;
};
class Display
{
private:
bool m_displayIntFirst;
public:
Display(bool displayIntFirst) { m_displayIntFirst = displayIntFirst; }
void displayItem(const Storage &storage)
{
if (m_displayIntFirst)
std::cout << storage.m_nValue << " " << storage.m_dValue << '\n';
else // display double first
std::cout << storage.m_dValue << " " << storage.m_nValue << '\n';
}
};
int main()
{
Storage storage(5, 6.7);
Display display(false);
display.displayItem(storage);
return 0;
}
Operator Overloading
In C++ each operator is actually a function. For example the operator +
is acturallyoperator+()
function.
- At least one of the operand will have to be a custom type
Using Friend Function
#include <iostream>
class Point{
private:
using point_t = int;
point_t m_x;
point_t m_y;
public:
Point(): m_x(0), m_y(0){}
Point(point_t x, point_t y): m_x(x), m_y(y){}
// constant memeber function
void print(void) const {
std::cout << "(" << m_x << ", " << m_y << ")" << "\n";
}
// This is not a member function only a friend function
// This could defined outside of the function too
friend Point operator+(cost Point &p, const int n){
return Point(p.m_x + n, p.m_y + n);
}
friend Point operator+(const int n, const Point &p){
return p + n;
}
friend Point operator+(const Point &p1, const Point &p2){
return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}
};
int main(int argc, char *argv[]){
Point p1(10, 20);
Point p2(4, 5);
Point p3 = p1 + p2 + 5;
p3.print();
return 0;
}
Using Normal Function
If there is no need to access private class data, operator overloading can be done as normal
function.
#include <iostream>
class Point{
private:
using point_t = int;
point_t m_x;
point_t m_y;
public:
Point(): m_x(0), m_y(0){}
Point(point_t x, point_t y): m_x(x), m_y(y){}
point_t getX(void) const {
return m_x;
}
point_t getY(void) const {
return m_y;
}
// constant memeber function
void print(void) const {
std::cout << "(" << m_x << ", " << m_y << ")" << "\n";
}
};
Point operator+(const Point &p, const int n){
return Point(p.getX() + n, p.getY() + n);
}
Point operator+(int n, const Point &p){
return p + n;
}
Point operator+(const Point &p1, const Point &p2){
return Point(p1.getX() + p2.getX(), p1.getY() + p2.getY());
}
int main(int argc, char *argv[]){
Point p1(10, 20);
Point p2(4, 5);
Point p3 = p1 + p2 + 5;
p3.print();
return 0;
}
Using Member Function
The assignment (=), subscript ([]), function call (()), and member selection (->) operators must be overloaded as member functions.
IO operators(<< and >>) can’t be overloaded as memeber functions.
#include <iostream>
class Point{
private:
using point_t = int;
point_t m_x;
point_t m_y;
public:
Point(): m_x(0), m_y(0){}
Point(point_t x, point_t y): m_x(x), m_y(y){}
// No need to pass the class explicitly as it will be passed as hidden this pointer
Point operator+ (int n){
return Point(m_x + n, m_y +n);
}
};
int main(int argc, char *argv[]){
Point p1(10, 20);
Point p2 = p1 + 5;
return 0;
}
Overloading IO operators
#include <iostream>
class Point{
private:
using point_t = int;
point_t m_x;
point_t m_y;
public:
Point(): m_x(0), m_y(0){}
Point(point_t x, point_t y): m_x(x), m_y(y){}
point_t getX(void){
return m_x;
}
point_t getY(void){
return m_y;
}
friend std::ostream& operator<< (std::ostream &out, const Point &p);
friend std::istream& operator>> (std::istream &in, Point &p);
};
// Overloading as friend function
// Returning std::ostream so that it can be chained like std::cout << p1 << p2
std::ostream& operator<< (std::ostream &out, const Point &p){
out << "(" << p.m_x << ", " << p.m_y << ")";
return out;
}
std::istream& operator>> (std::istream &in, Point &p){
in >> p.m_x >> p.m_y;
return in;
}
// Overloading as normal function
Point operator+ (Point p, int n){
return Point(p.getX() + n, p.getY() + n);
}
Point operator+ (int n, Point p){
return p + n;
}
Point operator+ (Point p1, Point p2){
return Point(p1.getX() + p2.getX(), p1.getY() + p2.getY());
}
int main(int argc, char *argv[]){
Point p1(10, 20);
Point p2;
std::cout << "Enter a point:\n";
std::cin >> p2;
std::cout << p1 << " + " << p2 << " = " << p1 + p2 << "\n";
return 0;
}
Functors
When classes acts like function calls they are called functors. This can be done by
overloading () operator.
#include <iostream>
class Point{
private:
using point_t = int;
point_t m_x;
point_t m_y;
public:
Point(): m_x(0), m_y(0){}
Point(point_t x, point_t y): m_x(x), m_y(y){}
point_t getX(void){
return m_x;
}
point_t getY(void){
return m_y;
}
// () can only be overloaded as member function
Point operator() (int n){
return Point(m_x + n, m_y + n);
}
friend std::ostream& operator<< (std::ostream &out, const Point &p);
};
// Overloading as friend function
// Returning std::ostream so that it can be chained like std::cout << p1 << p2
std::ostream& operator<< (std::ostream &out, const Point &p){
out << "(" << p.m_x << ", " << p.m_y << ")";
return out;
}
int main(int argc, char *argv[]){
Point pnt(10, 20);
// Will add 5 to pnt.m_x, pnt.m_y and create new Point object.
// Notce class object is called like function.
std::cout << pnt(5) << "\n";
return 0;
}
Overloading Typecast
Typecast overloading can be done to convert between types.
#include <iostream>
#include <cmath>
class Polar{
private:
double m_r;
double m_theta;
public:
Polar(double r, double theta): m_r(r), m_theta(theta){}
friend std::ostream& operator<< (std::ostream &out, const Polar &p);
};
// Overloading as friend function
// Returning std::ostream so that it can be chained like std::cout << p1 << p2
std::ostream& operator<< (std::ostream &out, const Polar &p){
out << "(" << p.m_r << ", " << p.m_theta << ")";
return out;
}
class Cartesian{
private:
using point_t = int;
point_t m_x;
point_t m_y;
public:
Cartesian(): m_x(0), m_y(0){}
Cartesian(point_t x, point_t y): m_x(x), m_y(y){}
friend std::ostream& operator<< (std::ostream &out, const Cartesian &c);
// Typecast overloading
operator Polar() const {
double r = sqrt(pow(m_x, 2) + pow(m_y, 2));
double theta = atan(static_cast<double>(m_y) / static_cast<double>(m_x));
theta = (theta * 180) / M_PI;
return Polar(r, theta);
}
};
std::ostream& operator<< (std::ostream &out, const Cartesian &c){
out << "(" << c.m_x << ", " << c.m_y << ")";
return out;
}
int main(int argc, char *argv[]){
Cartesian cart(10, 20);
Polar pol(cart);
std::cout << "Cartesian: " << cart << "\tPolar: " << pol << "\n";
return 0;
}
Copy Constructors
When copy initialization is used a copy constructor is used. By default
compiler uses memberwise initialization if no copy constructor is
provided. For example:
class Xyz {
private:
int m_var;
public:
Xyz(int x): m_var(x){}
};
int main(void){
Xyz xy(10); // uses default initialization
Xyz yz(xy); // Copy initialization
// As there is no copy constructor provided, compiler will do a memberwise initialization
}
Member functions of a class can access the private members ot
the same class type. Here is an example with copy constructor:
class Xyz {
private:
int m_var;
public:
Xyz(int x): m_var(x){}
// Copy constructor
Xyz(const Xyz &xyz): m_var(xyz.m_var){}
};
int main(void){
Xyz xy(10); // uses default initialization
Xyz yz(xy); // uses copy constructor
}
Elision
Copy initialization should be avoided as it can be elided
for optimization.
#include <iostream>
#include <string>
class Hello{
private:
std::string m_s;
public:
Hello(std::string s): m_s(s){}
Hello(const Hello &h): m_s(h.m_s){
std::cout << "Copy constructor called\n";
}
std::string get(void){return m_s;}
};
int main(int argc, char *argv[]){
Hello h("hello");
Hello g(h); // Copy constructor will be used
Hello i = Hello("gello"); // Copy constructor won't be used
Hello k(Hello("gello")); // Copy constructor won't be used
std::cout << h.get() << g.get() << i.get() << k.get() << "\n";
}
If a class is passed by value in a function and return by value from a function
copy constructor will be called. For example:
Hello changeHello(Hello h){ // Copy constructor will be called
h.change("new hello");
return h; // Copy constructor will be called
}
Implicit conversion, explicit and delete keyword
- explicit keyword can be used to prevent implicit conversion.
- delete keyword can be used to prevent both implicit and explicit conversion.
- For details
Overloading assignment operator
- Can only be oveloaded as memeber function.
- Watch out for self assignment.
- If no overloaded assignment operator is provided, compiler will do memberwise copy.
#include <iostream>
#include <string>
class Hello{
private:
std::string m_s;
public:
Hello(std::string s): m_s(s){}
Hello(const Hello &h): m_s(h.m_s){
std::cout << "Copy constructor called\n";
}
std::string get(void){return m_s;}
Hello& operator= (const Hello &h){
// If self copying
if(this == &h)
return *this; // for chainig
m_s = h.m_s;
return *this; // for chaining
}
};
int main(int argc, char *argv[]){
Hello h("hello");
Hello i("iello");
Hello j("jello");
Hello k(h); // Copy constructor is called
j = i = h; // Overloaded function is called
std::cout << h.get() << i.get() << j.get() << k.get() << "\n";
}
Shallow copy VS Deep copy
- Shallow copy means memberwise copying by the compiler if no copy constructor or overloaded assingment operator is provided.
- The default copy constructor and default assignment operators do shallow copies, which is fine for classes that contain no dynamically allocated variables.
- Classes with dynamically allocated variables need to have a copy constructor and assignment operator that do a deep copy.
Object Relationship
Composition and Aggregation
In both cases relationship between parent and child is ‘has a’.
Composition
- The part (member) is part of the object (class)
- The part (member) can only belong to one object (class) at a time
- The part (member) has its existence managed by the object (class)
- The part (member) does not know about the existence of the object (class)
- Typically use normal member variables
- Can use pointer members if the class handles object allocation/deallocation itself
- Responsible for creation/destruction of parts
Aggregation
- The part (member) is part of the object (class)
- The part (member) can belong to more than one object (class) at a time
- The part (member) does not have its existence managed by the object (class)
- The part (member) does not know about the existence of the object (class)
- Typically use pointer or reference members that point to or reference objects that live outside the scope of the aggregate class
- Not responsible for creating/destroying parts
Association
- The associated object (member) is otherwise unrelated to the object (class)
- The associated object (member) can belong to more than one object (class) at a time
- The associated object (member) does not have its existence managed by the object (class)
- The associated object (member) may or may not know about the existence of the object (class)
Dependencies
A dependency occurs when one object invokes another object’s functionality in order to accomplish some specific task.
This is a weaker relationship than an association, but still,
any change to object being depended upon may break functionality in the (dependent) caller.
A dependency is always a unidirectional relationship.
Container Classes
Hold and organize multiple instance of another type(class or fundamental type).
std::initializer_list
Used in container class’s constructor for list initialization.
Inheritance
Order of construction
Most base class constructed first and most derived class constructed last.
#include <iostream>
class Parent{
public:
Parent(){
std::cout << "A" << "\n";
}
};
class Child: public Parent{
public:
Child(){
std::cout << "B" << "\n";
}
};
int main(int argc, char *argv[]){
Child c;
return 0;
}
/*
* Will print:
* A
* B
*/
When a derived class is instanciated following things happen in order:
- Memory for derived is set aside (enough for both the Base and Derived portions)
- The appropriate Derived constructor is called
- The Base object is constructed first using the appropriate Base constructor. If no base constructor is specified, the default constructor will be used.
- The initialization list initializes variables
- The body of the constructor executes
- Control is returned to the caller
Constructors and initialization of derived classes
#include <iostream>
class Parent{
public:
int m_x;
Parent(int x=0): m_x(x){
std::cout << "A" << "\n";
}
};
class Child: public Parent{
public:
int m_y;
// Parent will be initialized with defautl vlaue
Child(int y=0): m_y(y){
std::cout << "B" << "\n";
}
// Parent will be initialized with given value
Child(int x, int y): Parent(x), m_y(y){
std::cout << "B" << "\n";
}
};
int main(int argc, char *argv[]){
// Parent's default constructor will be called
Child c(10);
// Parent will be initialized with given value
Child d(20, 10);
// Will print
// Parent 0
// Child 10
std::cout << "Parent " << c.m_x << "\nChild " << c.m_y << "\n";
// Will print
// Parent 20
// Child 10
std::cout << "Parent " << d.m_x << "\nChild " << d.m_y << "\n";
return 0;
}
When Child d(10, 20)
is called following things happended:
- Memory for Child is allocated.
- The Child(int, int) constructor is called, where x = 10, and y = 20
- The compiler looks to see if we’ve asked for a particular Base class constructor. We have! So it calls Parent(int) with x = 10.
- The base class constructor initialization list sets m_x to 10
- The base class constructor body executes, which prints A
- The base class constructor returns
- The derived class constructor initialization list sets m_y to 20
- The derived class constructor body executes, which prints B
- The derived class constructor returns
Order of Destruction
Destructors are called in reverse order of construction.
Inheritance and Access Specifiers
- public: Can be accessed by anybody.
- protected: Can be accessed by class member functions, friend functions and derived classes.
- private: Can be accessed by only class member functions and friend functions.
A summary of the behavious when inherited publicly, protectedly or privately:
Access Specifier in Base Class | Inherited Publicly | Inherited Protectedly | Inherited Privately |
---|---|---|---|
public | public | protected | private |
protected | protected | protected | private |
private | inaccessible | inaccessible | inaccessible |
Overriding Behavior
Redefining
#include <iostream>
class Base{
public:
Base(){}
void identify(void){
std::cout << "I am base\n";
}
};
class Derived: public Base{
public:
Derived(){}
void identify(void){
std::cout << "I am derived\n";
}
};
int main(int argc, char *argv[]){
Derived d;
// Will print I am derived
d.identify();
return 0;
}
- Redefined functions doesn’t inherite access specification from parent.
Expanding Existing Functionality
#include <iostream>
class Base{
public:
Base(){}
void identify(void){
std::cout << "I am base\n";
}
};
class Derived: public Base{
public:
Derived(){}
void identify(void){
// if scope isn't used Derived::identify() will be called
Base::identify();
std::cout << "I am derived\n";
}
};
int main(int argc, char *argv[]){
Derived d;
// Will print
// I am base
// I am derived
d.identify();
return 0;
}
Changing an Inherited Member’s Access Specification
#include <iostream>
class Base{
public:
Base(){}
protected:
// Only membes, friends and derived class can call
void identify(void){
std::cout << "I am base\n";
}
};
class Derived: public Base{
public:
Derived(){}
// Base::identify() is now public
using Base::identify;
};
int main(int argc, char *argv[]){
Base b;
Derived d;
// Error: can't call from here
b.identify();
// OK: as it is public in Derived class
d.identify();
return 0;
}
Functionality can be hidden by making it private in derived class.
#include <iostream>
class Base{
public:
Base(){}
void identify(void){
std::cout << "I am base\n";
}
};
class Derived: public Base{
public:
Derived(){}
private:
// Base::identify() is now private
using Base::identify;
};
int main(int argc, char *argv[]){
Base b;
Derived d;
// OK: as it is public in Base class.
b.identify();
// OK: as it is public in Derived class
d.identify();
return 0;
}
Multiple Inheritance
- Ambiguity can arise.
#include <iostream>
class USBDevice
{
private:
long m_id;
public:
USBDevice(long id)
: m_id(id)
{
}
long getID() { return m_id; }
};
class NetworkDevice
{
private:
long m_id;
public:
NetworkDevice(long id)
: m_id(id)
{
}
long getID() { return m_id; }
};
class WirelessAdapter: public USBDevice, public NetworkDevice
{
public:
WirelessAdapter(long usbId, long networkId)
: USBDevice(usbId), NetworkDevice(networkId)
{
}
};
int main()
{
WirelessAdapter c54G(5442, 181742);
std::cout << c54G.getID(); // Which getID() do we call?
// Can be solved using scope
std::cout << c54G.USBDevice::getID();
return 0;
}
- Diamond problem
Virtual Functions
Pointers to the Base Class of Derived Object
It is possible to create pointers to the base class of derived object.
But the pointers won’t be able to call member functions from the derived
class.
#include <iostream>
class Base{
public:
Base(){}
void identify(void){
std::cout << "I am base\n";
}
};
class Derived: public Base{
public:
Derived(){}
void identify(void){
std::cout << "I am derived\n";
}
};
int main(int argc, char *argv[]){
Derived *pd = new Derived();
// Pointer to base of derived object
Base *pb{pd};
// Will call Derived::indentify()
pd->identify();
// Will call Base::identify()
pb->identify();
return 0;
}
Use case for this could be in functions which takes derived class as parameter.
For each derived class a different functions have to be created. For example:
void report(Derived &d){
d.identify();
}
void report(AnotherDerived &ad){
ad.identify();
}
This problem can be solved using pointer/reference to base:
void report(Base &b){
b.identify();
}
int main(int argc, char *argv[]){
Derived d;
AnotherDerived ad;
report(d);
report(ad);
}
But the problem is in both cases Base::identify() will be called.
As pointer to base only can see memebers from base. This problem
can be solved using virtual functions.
Polymorphism
A virtual function is a special type of function that, when called,
resolves to the most-derived version of the function that exists between the base and derived class.
This capability is known as polymorphism. A derived function is considered a match if it has the same signature
(name, parameter types, and whether it is const) and return type as the base version of the function.
Such functions are called overrides.
#include <iostream>
class Base{
public:
Base(){}
virtual void identify(void){
std::cout << "I am base\n";
}
};
class Derived: public Base{
public:
Derived(){}
void identify(void){
std::cout << "I am derived\n";
}
};
class AnotherDerived: public Derived{
public:
AnotherDerived(){}
void identify(void){
std::cout << "I am another derived\n";
}
};
int main(int argc, char *argv[]){
AnotherDerived ad;
Base *bp = &ad;
// Both resolve to AnotherDerived::identify()
ad.identify();
bp->identify();
Derived d;
bp = &d;
// Resolve to Derived::identity() as it is the most derived class in this case
bp->identify();
return 0;
}
Another example:
#include <iostream>
#include <string>
class Base{
public:
Base(){}
virtual std::string getName(void) const {return "Base";}
};
class Derived: public Base{
public:
Derived(){}
virtual std::string getName(void) const {return "Derived";}
};
class AnotherDerived: public Derived{
public:
AnotherDerived(){}
virtual std::string getName(void) const {return "AnotherDerived";}
};
void report(Base &b){
std::cout << "I am " << b.getName() << "\n";
}
int main(int argc, char *argv[]){
Derived d;
AnotherDerived ad;
report(d);
report(ad);
return 0;
}
If you want to call functions from base class in virtual function just use
scope operator:
Derived d;
Base *bp = &d;
std::cout << bp->Base::getName() << "\n";
- Return type have to match between virtual functions.
- Never use virtual function in constructors and destructors.
override and final Specifiers
A derived virtual function is only considered override if
functino signature and return type matches exactly between
the virtual functions. override
specifier enforces virtualization of a function.
If signature and return type doesn’t match the compiler will
generate an error. If override
is used, no need to specifyvirtual
keyword.
Covariant Return Type
Destructors
In case of inheritance destructors should
always make virtual. Specially if there is
dynamically allocated memory involved. If
a derived class is converted to a base class
and then call delete, only base destructor will
be called. If dynamic memory is allocated in
derived class, this will leak memory.
Abstract Class, Pure Virtual Functions and Interface Class
Abstract class is a class wich is only used by the derived class. It can’t be
instantiated anywhere else.
A pure virtual function has no body at all. It is meant to be redefined in derived classes.
A class with pure virtual functions is an abstract class means it can’t be intantiated.
A pure virtual function may or may not have a body.
virtual void doSomething() = 0
In interface class has no member variables. All the functions are pure virtual.
Virtual Base Class
- Single Base class is shared by the derived classes.
- Solves diamond problem.
- Most derived class is responsible for constructing the virtual base class.
Example:
#include <iostream>
class PoweredDevice
{
public:
PoweredDevice(int power)
{
std::cout << "PoweredDevice: " << power << '\n';
}
};
class Scanner: virtual public PoweredDevice // note: PoweredDevice is now a virtual base class
{
public:
Scanner(int scanner, int power)
: PoweredDevice{ power } // this line is required to create Scanner objects, but ignored in this case
{
std::cout << "Scanner: " << scanner << '\n';
}
};
class Printer: virtual public PoweredDevice // note: PoweredDevice is now a virtual base class
{
public:
Printer(int printer, int power)
: PoweredDevice{ power } // this line is required to create Printer objects, but ignored in this case
{
std::cout << "Printer: " << printer << '\n';
}
};
class Copier: public Scanner, public Printer
{
public:
Copier(int scanner, int printer, int power)
: PoweredDevice{ power }, // PoweredDevice is constructed here
Scanner{ scanner, power }, Printer{ printer, power }
{
}
};
Object Slicing
Derived d;
Base b(d); // b will get the Base part from d. It is called object slicing
// Will call Base::doSomething() even if it is a virtual function
b.doSomething()
Base &b(d);
// Will call Derived::doSomething if it is a virtual function as b in reference to d
bp->doSomething()
- In general avoid slicing
std::reference_wrapper
Dynamic Casting
Dynamic casing is used for downcasting.
Workaround for Friend Functions
Only member functions can be virtualized. So friend functions
can’t be virtualized. For example:
#include <iostream>
class Base
{
public:
Base() {}
// Here's our overloaded operator<<
friend std::ostream& operator<<(std::ostream &out, const Base &b)
{
// Delegate printing responsibility for printing to member function print()
return b.print(out);
}
// We'll rely on member function print() to do the actual printing
// Because print is a normal member function, it can be virtualized
virtual std::ostream& print(std::ostream& out) const
{
out << "Base";
return out;
}
};
class Derived : public Base
{
public:
Derived() {}
// Here's our override print function to handle the Derived case
virtual std::ostream& print(std::ostream& out) const override
{
out << "Derived";
return out;
}
};
int main()
{
Base b;
std::cout << b << '\n';
Derived d;
std::cout << d << '\n'; // note that this works even with no operator<< that explicitly handles Derived objects
Base &bref = d;
std::cout << bref << '\n';
return 0;
}
Templates
Function Template
#include <iostream>
template <typename T>
T add(T x, T y){
return x + y;
}
int main(int argc, char *argv[]){
std::cout << add(1, 2) << "\n";
std::cout << add(1.5, 2.1) << "\n";
return 0;
}
For more than one type:
template <typename T1, typename T2>
void doSomething(T1 x, T1 y){
}
Class Template
#include <iostream>
#include <string>
template <class T>
class Value{
private:
T m_x;
public:
Value(T x): m_x(x){}
T get(void){return m_x;}
};
int main(int argc, char *argv[]){
Value<int> ival(10);
Value<double> dval(10.25);
Value<std::string> sval("hello");
std::cout << "ival: " << ival.get() << " dval: " << dval.get() << " sval: " << sval.get()
<< "\n";
return 0;
}
If template class definition and implementation are splitted into seperate files
linker error can be generated. To solve this following can be done:
- Definition and implementation in one file.
- Implementation in
*.inl
file and#include
in*.h
file.
For more details
Template Non-Type parameters
#include <iostream>
template <class T, int size> // size is the non-type parameter
class StaticArray
{
private:
// The non-type parameter controls the size of the array
T m_array[size];
public:
T* getArray();
T& operator[](int index)
{
return m_array[index];
}
};
// Showing how a function for a class with a non-type parameter is defined outside of the class
template <class T, int size>
T* StaticArray<T, size>::getArray()
{
return m_array;
}
int main()
{
// declare an integer array with room for 12 integers
StaticArray<int, 12> intArray;
// Fill it up in order, then print it backwards
for (int count=0; count < 12; ++count)
intArray[count] = count;
for (int count=11; count >= 0; --count)
std::cout << intArray[count] << " ";
std::cout << '\n';
// declare a double buffer with room for 4 doubles
StaticArray<double, 4> doubleArray;
for (int count=0; count < 4; ++count)
doubleArray[count] = 4.4 + 0.1*count;
for (int count=0; count < 4; ++count)
std::cout << doubleArray[count] << ' ';
return 0;
}
Template Specialization
If an exception is needed to make for an specific type.
#include <iostream>
#include <string>
#include <cstring>
char str[100];
template <class T>
T add(T x, T y){
return x + y;
}
// If it is an const char*
template<>
const char *add(const char *s1, const char *s2){
strcat(str, s1);
strcat(str, s2);
return str;
}
int main(int argc, char *argv[]){
std::cout << add(1, 2) << "\n";
std::cout << add(1.5, 2.2) << "\n";
std::cout << add("hello", "world") << "\n";
return 0;
}
Standard Template Library
Appendix A: Some Usefull Functions
decltype(s)
– Query the type of s
C++ 讲义
讲义第一部分
- C++概述
- 1.1 C++简介
- 1.2 C++起源
- 1.3 可移植性和标准
- 1.4 为什么C++会成功
- C++初识
- 2.1 简单的C++程序
- 2.1.1 c++ hello world
- 2.1.2 面向过程
- 2.1.3 面向对象
- 2.1.4 面向对象三大特性
- C++对C的扩展
- 3.1 ::作用域运算符
- 3.2 名字控制
- 3.3 全局变量检测增强
- 3.4 C++中所有的变量和函数都必须有类型
- 3.5 更严格的类型转换
- 3.6 struct类型加强
- 3.7 “新增”bool类型关键字
- 3.8 三目运算符功能增强
- 3.9 C/C++中的const
- 3.9.1 const概述
- 3.9.2 C/C++中const的区别
- const概述
- C中的const
- 尽量以const替换#define
- 3.10 引用(reference)
1. 引用基本用法
2. 函数中的引用
3. 引用的本质
4. 指针引用
5. 常量引用 - 3.11 练习作业
- 3.12 内联函数(inline function)
- 3.13 函数的默认参数
- 3.14 函数的占位参数
- 3.15 函数重载(overload)
- 3.15.1 函数重载概述
- 3.15.2 函数重载
- 3.15.3 extern “C”浅析
- 类和对象
- 4.1 类和对象的基本概念
- 4.1.1 C和C++中struct区别
- c语言struct只有变量
- c++语言struct 既有变量,也有函数
- 4.1.2 类的封装
- 4.1.3 将成员变量设置为private
- 4.1.4 课堂练习
- 4.1.1 C和C++中struct区别
- 4.2 面向对象程序设计案例
- 4.3 对象的构造和析构
- 4.4 C++面向对象模型初探
- 4.5 友元
- 4.6 运算符重载
- 4.7 继承和派生
- 4.8 多态
- 4.1 类和对象的基本概念
讲义第二部分
- 1.C++模板
- 2.C++类型转换
- C++异常
- c++输入和输出流
STL基础教程
- STL概论
- STL三大组件
- 常用容器
- 常用算法
- STL综合案例(学校演讲比赛)
C++简介
"c++"中的++来自于c语言中的递增运算符++,该运算符将变量加1。c++起初也叫"c with clsss".通过名称表明,c++是对C的扩展,因此c++是c语言的超集,这意味着任何有效的c程序都是有效的c++程序。c++程序可以使用已有的c程序库。
库是编程模块的集合,可以在程序中调用它们。库对很多常见的编程问题提供了可靠的解决方法,因此可以节省程序员大量的时间和工作量。
c++语言在c语言的基础上添加了面向对象编程和泛型编程的支持。c++继承了c语言高效,简洁,快速和可移植的传统。
c++融合了3种不同的编程方式:
- c语言代表的过程性语言.
- c++在c语言基础上添加的类代表的面向对象语言.
- c++模板支持的泛型编程。
c语言和c++语言的关系:
c++语言是在C语言的基础上,添加了面向对象、模板等现代程序设计语言的特性而发展起来的。两者无论是从语法规则上,还是从运算符的数量和使用上,都非常相似,所以我们常常将这两门语言统称为"C/C++"。
C语言和C++并不是对立的竞争关系:
- C++是C语言的加强,是一种更好的C语言。
- C++是以C语言为基础的,并且完全兼容C语言的特性。
c语言和C++语言的学习是可以相互促进。学好C语言,可以为我们将来进一步地学习C++语言打好基础,而C++语言的学习,也会促进我们对于C语言的理解,从而更好地运用C语言。
#### C/C++全栈笔记
- 进程间通讯(IPC)方法
- 管道(使用最简单)
- 信号(开销最小)
- 共享映射区(无血缘关系)
- 本地套接字(最稳定)
- 管道
管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:
1. 其本质是一个伪文件(实为内核缓冲区)
2. 由两个文件描述符引用,一个表示读端,一个表示写端。
3. 规定数据从管道的写端流入管道,从读端流出。
管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。
管道的局限性:
1. 数据一旦被读走,便不在管道中存在,不可反复读取。
2. 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
3. 只能在有公共祖先的进程间使用管道。
常见的通信方式有,单工通信、半双工通信、全双工通信。
pipe函数
- 信号
- 共享映射区
- 本地套接字
- 网络编程-网络基础
- 协议的概念
- 网络应用程序设计模式
- C/S模式
传统的网络应用设计模式,客户机(client)/服务器(server)模式。需要在通讯两端各自部署客户机和服务器来完成数据通信。
- B/S模式
浏览器()/服务器(server)模式。只需在一端部署服务器,而另外一端使用每台PC都默认配置的浏览器即可完成数据的传输。
- 优缺点
对于C/S模式来说,其优点明显。客户端位于目标主机上可以保证性能,将数据缓存至客户端本地,从而提高数据传输效率。且,一般来说客户端和服务器程序由一个开发团队创作,所以他们之间所采用的协议相对灵活。可以在标准协议的基础上根据需求裁剪及定制。例如,腾讯公司所采用的通信协议,即为ftp协议的修改剪裁版。
因此,传统的网络应用程序及较大型的网络应用程序都首选C/S模式进行开发。如,知名的网络游戏魔兽世界。3D画面,数据量庞大,使用C/S模式可以提前在本地进行大量数据的缓存处理,从而提高观感。
C/S模式的缺点也较突出。由于客户端和服务器都需要有一个开发团队来完成开发。工作量将成倍提升,开发周期较长。另外,从用户角度出发,需要将客户端安插至用户主机上,对用户主机的安全性构成威胁。这也是很多用户不愿使用C/S模式应用程序的重要原因。
B/S模式相比C/S模式而言,由于它没有独立的客户端,使用标准浏览器作为客户端,其工作开发量较小。只需开发服务器端即可。另外由于其采用浏览器显示数据,因此移植性非常好,不受平台限制。如早期的偷菜游戏,在各个平台上都可以完美运行。
B/S模式的缺点也较明显。由于使用第三方浏览器,因此网络应用支持受限。另外,没有客户端放到对方主机上,缓存数据不尽如人意,从而传输数据量受到限制。应用的观感大打折扣。第三,必须与浏览器一样,采用标准http协议进行通信,协议选择不灵活。
因此在开发过程中,模式的选择由上述各自的特点决定。根据实际需求选择应用程序设计模式。
- 分层模型
- OSI七层模型
1. 物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后再转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。
2. 数据链路层:定义了如何让格式化数据以帧为单位进行传输,以及如何让控制对物理介质的访问。这一层通常还提供错误检测和纠正,以确保数据的可靠传输。如:串口通信中使用到的115200、8、N、1
3. 网络层:在位于不同地理位置的网络中的两个主机系统之间提供连接和路径选择。Internet的发展使得从世界各站点访问信息的用户数大大增加,而网络层正是管理这种连接的层。
4. 传输层:定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。 主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。
5. 会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)。
6. 表示层:可确保一个系统的应用层所发送的信息可以被另一个系统的应用层读取。例如,PC程序与另一台计算机进行通信,其中一台计算机使用扩展二一十进制交换码(EBCDIC),而另一台则使用美国信息交换标准码(ASCII)来表示相同的字符。如有必要,表示层会通过使用一种通格式来实现多种数据格式之间的转换。
7. 应用层:是最靠近用户的OSI层。这一层为用户的应用程序(例如电子邮件、文件传输和终端仿真)提供网络服务。
- TCP/IP四层模型
TCP/IP网络协议栈分为应用层(Application)、传输层(Transport)、网络层(Network)和链路层(Link)四层。
- 协议格式
- TCP协议
- 网络名词术语解析
- SOCKET编程
Socket本身有“插座”的意思,在Linux环境下,用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。
既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。与管道类似的,Linux系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地进程间通信,而套接字多应用于网络进程间数据的传递。
套接字的内核实现较为复杂,不宜在学习初期深入学习。
在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。“IP地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socketpair就唯一标识一个连接。因此可以用Socket来描述网络连接的一对一关系。
在网络通信中,套接字一定是成对出现的。一端的发送缓冲区对应对端的接收缓冲区。我们使用同一个文件描述符索发送缓冲区和接收缓冲区。
TCP/IP协议最早在BSD UNIX上实现,为TCP/IP协议设计的应用层编程接口称为socket API。本章的主要内容是socket API,主要介绍TCP协议的函数接口,最后介绍UDP协议和UNIX Domain Socket的函数接口。
网络字节序
TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。
IP地址转换函数
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);
char *inet_ntoa(struct in_addr in);
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
网络套接字函数
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
domain:
AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址
AF_INET6 与上面类似,不过是来用IPv6的地址
AF_UNIX 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用
type:
SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。
SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。
SOCK_SEQPACKET该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。
SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序
protocol:
传0 表示使用默认协议。
返回值:
成功:返回指向新创建的socket的文件描述符,失败:返回-1,设置errno
#### 传智云盘项目
- 分布式存储FastDFS
- 缓存数据库redis
- 持久化数据库mysql
- HTTP协议
- Nginx
- FastCGI
- CGI
通用网关接口(Common Gateway Interface、CGI)描述了客户端和服务器程序之间传输数据的一种标准,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。
CGI独立于任何语言的,CGI程序可以用任何脚本语言或者是完全独立编程语言实现,只要这个语言可以在这个系统上运行。Unix shell script、Python、 Ruby、PHP、 perl、Tcl、 C/C++和 Visual Basic 都可以用来编写 CGI 程序。
最初,CGI 是在 1993 年由美国国家超级电脑应用中心(NCSA)为 NCSA HTTPd Web 服务器开发的。这个 Web 服务器使用了 UNIX shell 环境变量来保存从 Web 服务器传递出去的参数,然后生成一个运行 CGI 的独立的进程。
CGI处理流程
1. web服务器收到客户端(浏览器)的请求Http Request,启动CGI程序,并通过环境变量、标准输入传递数据
2. CGI进程启动解析器、加载配置(如业务相关配置)、连接其它服务器(如数据库服务器)、逻辑处理等
3. CGI进程将处理结果通过标准输出、标准错误,传递给web服务器
4. web服务器收到CGI返回的结果,构建Http Response返回给客户端,并杀死CGI进程
CGI使外部程序与Web服务器之间交互成为可能。CGI程序运行在独立的进程中,并对每个Web请求建立一个进程,这种方法非常容易实现,但效率很差,难以扩展。面对大量请求,进程的大量建立和消亡使操作系统性能大大下降。此外,由于地址空间无法共享,也限制了资源重用。
- FastCGI
快速通用网关接口(Fast Common Gateway Interface/FastCGI)是通用网关接口(CGI)的改进,描述了客户端和服务器程序之间传输数据的一种标准。
FastCGI致力于减少Web服务器与CGI程式之间互动的开销,从而使服务器可以同时处理更多的Web请求。与为每个请求创建一个新的进程不同,FastCGI使用持续的进程来处理一连串的请求。这些进程由FastCGI进程管理器管理,而不是web服务器。
FastCGI处理流程
1. Web 服务器启动时载入初始化FastCGI执行环境。 例如IIS、ISAPI、apache mod_fastcgi、nginx ngx_http_fastcgi_module、lighttpd mod_fastcgi。
2. FastCGI进程管理器自身初始化,启动多个CGI解释器进程并等待来自Web服务器的连接。启动FastCGI进程时,可以配置以ip和UNIX 域socket两种方式启动。
3. 当客户端请求到达Web 服务器时,Web服务器将请求采用socket方式转发FastCGI主进程,FastCGI主进程选择并连接到一个CGI解释器。Web 服务器将CGI环境变量和标准输入发送到FastCGI子进程。
4. FastCGI子进程完成处理后将标准输出和错误信息从同一socket连接返回Web服务器。当FastCGI子进程关闭连接时,请求便处理完成。
5. FastCGI子进程接着等待并处理来自Web 服务器的下一个连接。
由于FastCGI程序并不需要不断的产生新进程,可以大大降低服务器的压力并且产生较高的应用效率。它的速度效率最少要比CGI 技术提高 5 倍以上。它还支持分布式的部署,即FastCGI 程序可以在web 服务器以外的主机上执行。
CGI 是所谓的短生存期应用程序,FastCGI 是所谓的长生存期应用程序。FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,不会每次都要花费时间去fork一次(这是CGI最为人诟病的fork-and-execute 模式)。
进程管理器管理:spawn-fcgi
Nginx不能像Apache那样直接执行外部可执行程序,但Nginx可以作为代理服务器,将请求转发给后端服务器,这也是Nginx的主要作用之一。其中Nginx就支持FastCGI代理,接收客户端的请求,然后将请求转发给后端FastCGI进程。
由于FastCGI进程由FastCGI进程管理器管理,而不是Nginx。这样就需要一个FastCGI进程管理器,管理我们编写FastCGI程序。
spawn-fcgi是一个通用的FastCGI进程管理器,简单小巧,原先是属于lighttpd的一部分,后来由于使用比较广泛,所以就迁移出来作为独立项目。
spawn-fcgi使用pre-fork 模型,功能主要是打开监听端口,绑定地址,然后fork-and-exec创建我们编写的FastCGI应用程序进程,退出完成工作。FastCGI应用程序初始化,然后进入死循环侦听socket的连接请求。
编译安装spawn-fcgi
1. tar -zxvf spawn-fcgi-1.6.4.tar.gz
2. cd spawn-fcgi-1.6.4/
3. ./configure
4. make
5. sudo make install
软件开发套件:fcgi
编译安装fcgi
1. tar -zxvf fcgi-2.4.1-SNAP-0910052249.tar.gz
2. cd fcgi-2.4.1-SNAP-0910052249/
3. ./configure
4. make
5. sudo make install
Nginx的fcgi的配置
- FastDFS的Nginx模块
一个好的分布式文件系统最好提供Nginx的模块,因为对于互联网应用来说,像文件这种静态资源,一般是通过HTTP的下载,此时通过容易扩展的Nginx来访问FastDFS,能够让文件的上传和下载变得特别简单。
Nginx安装FastDFS模块,主要是安装在FastDFS的存储服务器(storage)上,而不是tracker和client上。目的实际是为了,当输入地址(其中192.168.31.109 是一个storage服务器):http://192.168.31.109/group1/M00/00/00/wKgCbFem0l2ALSbFAAEYXfRAMkc536.png
能够通过Nginx的Web服务功能,直接返回图片。
- QT客户端编程
- 后台数据处理
STL基础教程
STL基础教程
- STL概论
- STL三大组件
- 常用容器
- string
- vector
vect(T) v; vector(v.begin(), v.end()); vector(n,elem); vector(const vector & vec);
assign(beg, end); assign(n, elem); vector& operater=(const vector & vec); swap(vec);
size() empty() resize(int num) capacity() reserve(int len)
at(int idx); operater[]; front(); back();
insert(const_iterator pos, int count,ele); push_back(ele); pop_back(); erase(const_iterator start, const_iterator end); erase(const_iterator pos); clear();
- deque
- 构造函数
deque<T> deqT;//默认构造形式
deque(beg, end);//构造函数将[beg, end)区间中的元素拷贝给本身。
deque(n, elem);//构造函数将n个elem拷贝给本身。
deque(const deque &deq);//拷贝构造函数。
- 赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
deque& operator=(const deque &deq); //重载等号操作符
swap(deq);// 将deq与本身的元素互换
- 大小操作
deque.size();//返回容器中元素的个数
deque.empty();//判断容器是否为空
deque.resize(num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除。
- 双端插入和删除操作
push_back(elem);//在容器尾部添加一个数据
push_front(elem);//在容器头部插入一个数据
pop_back();//删除容器最后一个数据
pop_front();//删除容器第一个数据
- 数据存取
at(idx);//返回索引idx所指的数据,如果idx越界,抛出out_of_range。
operator[];//返回索引idx所指的数据,如果idx越界,不抛出异常,直接出错。
front();//返回第一个数据。
back();//返回最后一个数据
- 插入操作
insert(pos,elem);//在pos位置插入一个elem元素的拷贝,返回新数据的位置。
insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
- 删除操作
clear();//移除容器的所有数据
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos);//删除pos位置的数据,返回下一个数据的位置。
- 构造函数
- stack
- queue
- list
- set/multiset
- map/multimap
- 常用算法
- STL综合案例
STL基础教程
<>笔记 still
总结
- 定义一些模板类,这些类是一些策略,定义了一些接口,它们比较松散
概念:
- 策略polices: 用来定义一个class或class template的接口,该接口由夏磊项目之一或全部组成:内隐型别定义(inner type definition),成员函数和成员变量
- hosts或host classes(主或主类): 如果class采用一个或多个policess,称为hosts或host classes
#include <iostream>
//下面是三个策略,用不同方式创建模板参数类型的对象
template <class T>
struct OpNewCreator {
static T* Create() {
return new T;
}
};
template <class T>
struct MallocCreator {
static T* Create() {
void* buf = std::malloc(sizeof(T));
if (!buf) return 0;
return new(buf) T;
}
};
template <class T>
struct PrototypeCreator {
PrototypeCreator(T* pObj = 0) : pPrototype_(pObj) {}
T* Create() {
return pPrototype_ ? pPrototype_->Clone() : 0;
}
T* GetPrototype() { return pPrototype_; }
void SetPrototype(T* pObj) { pPrototype_ = pObj; }
private:
T* pPrototype_;
};
//具体可能需要创建对象的一个类
class Widget {};
# if 0
template <class CreationPolicy> //一个模板类,继承模板参数类型,模板参数就是要选择的策略类,策略类也是模板类
class WidgetManager : public CreationPolicy {};
//定义一个类型,该类型客户端传入一个期望的策略OpNewCreator,通过该类型产生选择该策略的实例
typedef WidgetManager< OpNewCreator<Widget> > MyWidgetMgr; //模板参数是一个模板类,需要指明类型
#elif 0
//上面客户端多传了一个Widget, 修改使用策略的类,优化掉Widget,使用template template参数
template <template <class Created> class CreationPolicy>
class WidgetManager : public CreationPolicy<Widget> {}; //前面已指明继承的类是模板参数(类型),模板参数也是模板类,需要传递实参数Widget
typedef WidgetManager< OpNewCreator > MyWidgetMgr; //应用代码,不用再传模板参数的参数
#elif 0
template <template <class> class CreationPolicy> //Created是形参,可以省略不写
class WidgetManager : public CreationPolicy<Widget> {};
typedef WidgetManager< OpNewCreator > MyWidgetMgr; //应用代码
#elif 0
class Gadget {
};
template <template <class> class CreationPolicy> //选用相同策略生成一个Gadget对象
class WidgetManager : public CreationPolicy<Widget> {
public:
void DoSomething() {
Gadget* pW = CreationPolicy<Gadget>().Create();
std::cout << "Hello template!" << pW << std::endl;
}
};
typedef WidgetManager< OpNewCreator > MyWidgetMgr; //应用代码
#elif 1
template< template <class> class CreationPolicy = OpNewCreator> //提供默认策略
class WidgetManager : public CreationPolicy<Widget> {
public:
void DoSomething() {
Gadget* pW = CreationPolicy<Gadget>().Create();
std::cout << "Hello template!" << pW << std::endl;
}
};
#endif
vincehuston
设计模式
// Purpose. Abstract Factory #include <iostream.h>
//
// Discussion. Trying to maintain class Widget { public:
// portability across multiple "plat- virtual void draw() = 0;
// forms" routinely requires lots of };
// preprocessor "case" stmts. The
// Factory pattern suggests defining class MotifBtn : public Widget {
// a creation services interface in a public:
// Factory base class, and implement- void draw() { cout << "MotifBtn"
// ing each "platform" in a separate << endl; }
// Factory derived class. };
#include <iostream.h> class WindowsBtn : public Widget {
public:
class Widget { public: void draw() { cout << "WindowsBtn"
virtual void draw() = 0; << endl; }
}; };
class MotifBtn : public Widget { class Factory { public:
public: virtual Widget* createBtn() = 0;
void draw() { cout << "MotifBtn" };
<< endl; }
}; class MotifFactory : public Factory {
public:
class WindowsBtn : public Widget { Widget* createBtn() {
public: return new MotifBtn; }
void draw() { cout << "WindowsBtn" };
<< endl; }
}; class WindowsFactory : public Factory {
public:
void doThisWindow() { Widget* createBtn() {
// create window, attach btn return new WindowsBtn; }
#ifdef MOTIF };
Widget* w = new MotifBtn;
#else // WINDOWS Factory* factory;
Widget* w = new WindowsBtn;
#endif void doThisWindow() {
w->draw(); } // create window, attach btn
Widget* w = factory->createBtn();
void doThatWindow() { w->draw(); }
// create window, attach btn
#ifdef MOTIF void doThatWindow() {
Widget* w = new MotifBtn; // create window, attach btn
#else // WINDOWS Widget* w = factory->createBtn();
Widget* w = new WindowsBtn; w->draw(); }
#endif
w->draw(); } void main( void )
{
void main( void ) #ifdef MOTIF
{ factory = new MotifFactory;
// create window, attach btn #else // WINDOWS
#ifdef MOTIF factory = new WindowsFactory;
Widget* w = new MotifBtn; #endif
#else // WINDOWS
Widget* w = new WindowsBtn; // create window, attach btn
#endif Widget* w = factory->createBtn();
w->draw(); w->draw();
doThisWindow(); doThisWindow();
doThatWindow(); doThatWindow();
} }
// WindowsBtn // MotifBtn
// WindowsBtn // MotifBtn
// WindowsBtn // MotifBtn
// Purpose. Abstract Factory design pattern demo.
//
// Discussion. "Think of constructors as factories that churn out objects".
// Here we are allocating the constructor responsibility to a factory object,
// and then using inheritance and virtual member functions to provide a
// "virtual constructor" capability. So there are two dimensions of
// decoupling occurring. The client uses the factory object instead of "new"
// to request instances; and, the client "hard-wires" the family, or class, of
// that factory only once, and throughout the remainder of the application
// only relies on the abstract base class.
#include <iostream.h>
class Shape {
public:
Shape() { id_ = total_++; }
virtual void draw() = 0;
protected:
int id_;
static int total_;
};
int Shape::total_ = 0;
class Circle : public Shape { public:
void draw() { cout << "circle " << id_ << ": draw" << endl; } };
class Square : public Shape { public:
void draw() { cout << "square " << id_ << ": draw" << endl; } };
class Ellipse : public Shape { public:
void draw() { cout << "ellipse " << id_ << ": draw" << endl; } };
class Rectangle : public Shape { public:
void draw() { cout << "rectangle " << id_ << ": draw" << endl; } };
class Factory { public:
virtual Shape* createCurvedInstance() = 0;
virtual Shape* createStraightInstance() = 0;
};
class SimpleShapeFactory : public Factory { public:
Shape* createCurvedInstance() { return new Circle; }
Shape* createStraightInstance() { return new Square; }
};
class RobustShapeFactory : public Factory { public:
Shape* createCurvedInstance() { return new Ellipse; }
Shape* createStraightInstance() { return new Rectangle; }
};
void main() {
#ifdef SIMPLE
Factory* factory = new SimpleShapeFactory;
#elif ROBUST
Factory* factory = new RobustShapeFactory;
#endif
Shape* shapes[3];
shapes[0] = factory->createCurvedInstance(); // shapes[0] = new Ellipse;
shapes[1] = factory->createStraightInstance(); // shapes[1] = new Rectangle;
shapes[2] = factory->createCurvedInstance(); // shapes[2] = new Ellipse;
for (int i=0; i < 3; i++)
shapes[i]->draw();
}
// ellipse 0: draw
// rectangle 1: draw
// ellipse 2: draw
// Purpose. Builder class Builder { public:
// virtual void addFront( char ) = 0;
// The monolithic design supports a virtual void addBack( char ) = 0;
// single representation. The Builder virtual Array& getResult() = 0;
// design allows a different rep per };
// Builder derived class, and the com-
// mon input and parsing have been de- class BuilderOne : public Builder {
// fined in the Director class. The D public:
// constructs, the B returns result. void addFront( char ch ) {
one.lst.push_back( ch ); }
class Array { void addBack( char ch ) {
public: one.lst.push_back( ch ); }
void addFront( char ch ) { Array& getResult() {
lst.push_front( ch ); } return one; }
void addBack( char ch ) { private:
lst.push_back( ch ); } OneEnded one;
void traverse() { };
for (i=0; i < lst.size(); i++)
cout << lst[i] << ' '; class BuilderTwo : public Builder {
cout << endl; } public:
private: void addFront( char ch ) {
deque<char> lst; int i; two.lst.push_front( ch ); }
}; void addBack( char ch ) {
two.lst.push_back( ch ); }
string in[] = { "fa", "bb", "fc", Array& getResult() {
"bd", "fe", "bf", "fg", "bh" }; return two; }
private:
void main( void ) { TwoEnded two;
Array list; };
for (int i=0; i < 8; i++)
if (in[i][0] == 'f') string in[] = { "fa", "bb", "fc",
list.addFront( in[i][1] ); "bd", "fe", "bf", "fg", "bh" };
else if (in[i][0] == 'b')
list.addBack( in[i][1] ); class Director {
list.traverse(); } public:
Director( Builder* b ) {
// g e c a b d f h setBuilder( b ); }
void setBuilder( Builder* b ) {
///////////////////\\\\\\\\\\\\\\\\\\\ bldr = b; }
void construct() {
class Array { public: for (int i=0; i < 8; i++)
virtual void traverse() = 0; if (in[i][0] == 'f')
}; bldr->addFront(in[i][1]);
else if (in[i][0] == 'b')
class OneEnded : public Array { bldr->addBack(in[i][1]);
public: }
friend class BuilderOne; private:
void traverse() { Builder* bldr;
for (i=0; i < lst.size(); i++) };
cout << lst[i] << ' ';
cout << endl; } void main( void ) {
private: BuilderOne one;
vector<char> lst; int i; BuilderTwo two;
}; Director dir( &one );
class TwoEnded : public Array { dir.construct();
public: one.getResult().traverse();
friend class BuilderTwo; dir.setBuilder( &two );
void traverse() { dir.construct();
for (i=0; i < lst.size(); i++) two.getResult().traverse();
cout << lst[i] << ' '; }
cout << endl; }
private: // a b c d e f g h
deque<char> lst; int i; // g e c a b d f h
};
// Purpose. Builder design pattern demo.
//
// Discussion. The forte of Builder is constructing a complex object step
// by step. An abstract base class declares the standard construction
// process, and concrete derived classes define the appropriate
// implementation for each step of the process. In this example,
// "distributed work packages" have been abstracted to be persistent and
// platform independent. This means that the platform-specific mechanism
// for implementing files, queues, and concurrency pathways is defined in
// each platform's concrete derived class. A single "reader" object (i.e.
// parser) retrieves the archived specification for a DistrWorkPackage and
// proceeds to delegate each build step to the builder object that was
// registered by the client. Upon completion, the client retrieves the
// end result from the builder.
#include <iostream.h>
#include <stdio.h>
#include <string.h>
enum PersistenceType { File, Queue, Pathway };
struct PersistenceAttribute {
PersistenceType type;
char value[30];
};
class DistrWorkPackage {
public:
DistrWorkPackage( char* type ) {
sprintf( _desc, "Distributed Work Package for: %s", type); }
void setFile ( char* f, char* v ) {
sprintf( _temp, "\n File(%s): %s", f, v );
strcat( _desc, _temp); }
void setQueue ( char* q, char* v ) {
sprintf( _temp, "\n Queue(%s): %s", q, v );
strcat( _desc, _temp); }
void setPathway( char* p, char* v ) {
sprintf( _temp, "\n Pathway(%s): %s", p, v );
strcat(_desc,_temp); }
const char* getState() { return _desc; }
private:
char _desc[200], _temp[80];
};
class Builder {
public:
virtual void configureFile( char* ) = 0;
virtual void configureQueue( char* ) = 0;
virtual void configurePathway( char* ) = 0;
DistrWorkPackage* getResult() { return _result; }
protected:
DistrWorkPackage* _result;
};
class UnixBuilder : public Builder {
public:
UnixBuilder() { _result = new DistrWorkPackage( "Unix" ); }
void configureFile( char* name ) {
_result->setFile( "flatFile", name ); }
void configureQueue( char* queue ) {
_result->setQueue( "FIFO", queue ); }
void configurePathway( char* type ) {
_result->setPathway( "thread", type ); }
};
class VmsBuilder : public Builder {
public:
VmsBuilder() { _result = new DistrWorkPackage( "Vms" ); }
void configureFile( char* name ) {
_result->setFile( "ISAM", name ); }
void configureQueue( char* queue ) {
_result->setQueue( "priority", queue ); }
void configurePathway( char* type ) {
_result->setPathway( "LWP", type ); }
};
class Reader {
public:
void setBuilder( Builder* b ) { _builder = b; }
void construct( PersistenceAttribute[], int );
private:
Builder* _builder;
};
void Reader::construct( PersistenceAttribute list[], int num ) {
for (int i=0; i < num; i++)
if (list[i].type == File)
_builder->configureFile( list[i].value );
else if (list[i].type == Queue)
_builder->configureQueue( list[i].value );
else if (list[i].type == Pathway)
_builder->configurePathway( list[i].value ); }
const int NUM_ENTRIES = 6;
PersistenceAttribute input[NUM_ENTRIES] = { {File, "state.dat"},
{File,"config.sys"}, {Queue, "compute"}, {Queue, "log"},
{Pathway, "authentication"}, {Pathway, "error processing"} };
void main() {
UnixBuilder unixBuilder;
VmsBuilder vmsBuilder;
Reader reader;
reader.setBuilder( &unixBuilder );
reader.construct( input, NUM_ENTRIES );
cout << unixBuilder.getResult()->getState() << endl;
reader.setBuilder( &vmsBuilder );
reader.construct( input, NUM_ENTRIES );
cout << vmsBuilder.getResult()->getState() << endl;
}
// Distributed Work Package for: Unix
// File(flatFile): state.dat
// File(flatFile): config.sys
// Queue(FIFO): compute
// Queue(FIFO): log
// Pathway(thread): authentication
// Pathway(thread): error processing
// Distributed Work Package for: Vms
// File(ISAM): state.dat
// File(ISAM): config.sys
// Queue(priority): compute
// Queue(priority): log
// Pathway(LWP): authentication
// Pathway(LWP): error processing
// Purpose. Factory Method #include <iostream>
// creation via inheritance using namespace std;
//
// Discussion. The architect has done class Stooge {
// an admirable job of decoupling the public:
// client from Stooge concrete derived virtual void slapStick() = 0;
// classes, and, exercising polymor- };
// phism. But there remains coupling
// where instances are actually class Factory {
// created. If we design an "extra public:
// level of indirection" (a "factory // Factory Method (virtual ctor)
// method") and have clients use it static Stooge* create( int );
// (instead of "new"), then the last };
// bit of coupling goes away. The
// "factory method" (aka "virtual void main( void ) {
// constructor") can be defined in the Stooge* roles[10];
// Stooge base class, or, in a int in, j, i = 0;
// separate "factory" class. Note
// that main() is no longer dependent while (1) {
// on Stooge derived classes. cout << "L(1) M(2) C(3) Go(0): ";
cin >> in;
#include <iostream> if ( ! in ) break;
using namespace std; roles[i++] = Factory::create(in);
}
class Stooge { public: for (j=0; j < i; j++)
virtual void slapStick() = 0; roles[j]->slapStick();
}; for (j=0; j < i; j++)
delete roles[j];
class Larry : public Stooge { public: }
void slapStick() {
cout << "Larry: poke eyes" class Larry : public Stooge { public:
<< endl; } void slapStick() {
}; cout << "Larry: poke eyes"
class Moe : public Stooge { public: << endl; }
void slapStick() { };
cout << "Moe: slap head" class Moe : public Stooge { public:
<< endl; } void slapStick() {
}; cout << "Moe: slap head"
class Curly : public Stooge { public: << endl; }
void slapStick() { };
cout << "Curly: suffer abuse" class Curly : public Stooge { public:
<< endl; } void slapStick() {
}; cout << "Curly: suffer abuse"
<< endl; }
void main( void ) { };
Stooge* roles[10];
int in, j, i = 0; Stooge* Factory::create( int in ) {
if (in == 1)
cout << "L(1) M(2) C(3) Go(0): "; return new Larry;
cin >> in; else if (in == 2)
while (in) { return new Moe;
if (in == 1) else
roles[i++] = new Larry; return new Curly;
else if (in == 2) }
roles[i++] = new Moe;
else // L(1) M(2) C(3) Go(0): 1
roles[i++] = new Curly; // L(1) M(2) C(3) Go(0): 2
cout << "L(1) M(2) C(3) Go(0): "; // L(1) M(2) C(3) Go(0): 3
cin >> in; // L(1) M(2) C(3) Go(0): 1
} // L(1) M(2) C(3) Go(0): 0
for (j=0; j < i; j++) // Larry: poke eyes
roles[j]->slapStick(); // Moe: slap head
for (j=0; j < i; j++) // Curly: suffer abuse
delete roles[j]; // Larry: poke eyes
}
// Purpose. Factory Method design pattern demo.
//
// Discussion. Frameworks are applications (or subsystems) with "holes"
// in them. Each framework specifies the infrastructure, superstructure,
// and flow of control for its "domain", and the client of the framework
// may: exercise the framework's default behavior "as is", extend selected
// pieces of the framework, or replace selected pieces. The Factory
// Method pattern addresses the notion of "creation" in the context of
// frameworks. In this example, the framework knows WHEN a new document
// should be created, not WHAT kind of Document to create. The
// "placeholder" Application::CreateDocument() has been declared by the
// framework, and the client is expected to "fill in the blank" for
// his/her specific document(s). Then, when the client asks for
// Application::NewDocument(), the framework will subsequently call the
// client's MyApplication::CreateDocument().
#include <iostream.h>
/* Abstract base class declared by framework */
class Document {
public:
Document( char* fn ) { strcpy( name, fn ); }
virtual void Open() = 0;
virtual void Close() = 0;
char* GetName() { return name; }
private:
char name[20];
};
/* Concrete derived class defined by client */
class MyDocument : public Document {
public:
MyDocument( char* fn ) : Document(fn) { }
void Open() { cout << " MyDocument: Open()" << endl; }
void Close() { cout << " MyDocument: Close()" << endl; }
};
/* Framework declaration */
class Application {
public:
Application() : _index(0) { cout << "Application: ctor" << endl; }
/* The client will call this "entry point" of the framework */
NewDocument( char* name ) {
cout << "Application: NewDocument()" << endl;
/* Framework calls the "hole" reserved for client customization */
_docs[_index] = CreateDocument( name );
_docs[_index++]->Open(); }
OpenDocument() { }
void ReportDocs();
/* Framework declares a "hole" for the client to customize */
virtual Document* CreateDocument( char* ) = 0;
private:
int _index;
/* Framework uses Document's base class */
Document* _docs[10];
};
void Application::ReportDocs() {
cout << "Application: ReportDocs()" << endl;
for (int i=0; i < _index; i++)
cout << " " << _docs[i]->GetName() << endl; }
/* Customization of framework defined by client */
class MyApplication : public Application {
public:
MyApplication() { cout << "MyApplication: ctor" << endl; }
/* Client defines Framework's "hole" */
Document* CreateDocument( char* fn ) {
cout << " MyApplication: CreateDocument()" << endl;
return new MyDocument( fn ); }
};
void main() {
/* Client's customization of the Framework */
MyApplication myApp;
myApp.NewDocument( "foo" );
myApp.NewDocument( "bar" );
myApp.ReportDocs();
}
// Application: ctor
// MyApplication: ctor
// Application: NewDocument()
// MyApplication: CreateDocument()
// MyDocument: Open()
// Application: NewDocument()
// MyApplication: CreateDocument()
// MyDocument: Open()
// Application: ReportDocs()
// foo
// bar
// Purpose. Prototype #include <iostream.h>
// creation via delegation
// Discussion. The architect has done class Stooge { public:
// an admirable job of decoupling the virtual Stooge* clone() = 0;
// client from Stooge concrete derived virtual void slapStick() = 0;
// classes and exercising polymor- };
// phism. But there remains coup-
// ling where instances are actually class Factory {
// created. If we design an "extra public:
// level of indirection" (a "factory") static Stooge* create( int i );
// and have clients use it (instead of private:
// "new"), then the last bit of coup- static Stooge* prototypes_[4];
// ling goes away. The Prototype };
// pattern suggests delegating the
// creation service to contained ob- void main( void )
// jects that know how to "clone" {
// themselves. This strategy also Stooge* roles[10];
// allows us to retire the "case" int in, j, i = 0;
// statement in main().
cout << "L(1) M(2) C(3) Go(0): ";
#include <iostream.h> cin >> in;
while (in) {
class Stooge { public: roles[i++] = Factory::create(in);
virtual void slapStick() = 0; cout << "L(1) M(2) C(3) Go(0): ";
}; cin >> in; }
class Larry : public Stooge { public: for (j=0; j < i; j++)
void slapStick() { roles[j]->slapStick();
cout << "Larry: poke eyes"
<< endl; } for (j=0; j < i; j++)
}; delete roles[j];
class Moe : public Stooge { public: }
void slapStick() {
cout << "Moe: slap head" class Larry : public Stooge { public:
<< endl; } Stooge* clone() { return new Larry; }
}; void slapStick() {
class Curly : public Stooge { public: cout << "Larry: poke eyes"
void slapStick() { << endl; }
cout << "Curly: suffer abuse" };
<< endl; } class Moe : public Stooge { public:
}; Stooge* clone() { return new Moe; }
void slapStick() {
void main( void ) cout << "Moe: slap head"
{ << endl; }
Stooge* roles[10]; };
int in, j, i = 0; class Curly : public Stooge { public:
Stooge* clone() {return new Curly; }
cout << "L(1) M(2) C(3) Go(0): "; void slapStick() {
cin >> in; cout << "Curly: suffer abuse"
while (in) { << endl; }
if (in == 1) };
roles[i++] = new Larry;
else if (in == 2) Stooge* Factory::prototypes_[] = { 0,
roles[i++] = new Moe; new Larry, new Moe, new Curly };
else Stooge* Factory::create( int i ) {
roles[i++] = new Curly; return prototypes_[i]->clone(); }
cout << "L(1) M(2) C(3) Go(0): ";
cin >> in; } // L(1) M(2) C(3) Go(0): 1
// L(1) M(2) C(3) Go(0): 2
for (j=0; j < i; j++) // L(1) M(2) C(3) Go(0): 3
roles[j]->slapStick(); // L(1) M(2) C(3) Go(0): 1
// L(1) M(2) C(3) Go(0): 0
for (j=0; j < i; j++) // Larry: poke eyes
delete roles[j]; // Moe: slap head
} // Curly: suffer abuse
// Larry: poke eyes
//////////////////// Same example, single column \\\\\\\\\\\\\\\\\\\\
// Purpose. Prototype
// creation via delegation
// Discussion. The architect has done
// an admirable job of decoupling the
// client from Stooge concrete derived
// classes and exercising polymor-
// phism. But there remains coup-
// ling where instances are actually
// created. If we design an "extra
// level of indirection" (a "factory")
// and have clients use it (instead of
// "new"), then the last bit of coup-
// ling goes away. The Prototype
// pattern suggests delegating the
// creation service to contained ob-
// jects that know how to "clone"
// themselves. This strategy also
// allows us to retire the "case"
// statement in main().
#include <iostream>
using namespace std;
class Stooge {
public:
virtual void slapStick() = 0;
};
class Larry : public Stooge {
public:
void slapStick() {
cout << "Larry: poke eyes" << endl; }
};
class Moe : public Stooge {
public:
void slapStick() {
cout << "Moe: slap head" << endl; }
};
class Curly : public Stooge {
public:
void slapStick() {
cout << "Curly: suffer abuse" << endl; }
};
int main( void ) {
Stooge* roles[10];
int in, j, i = 0;
cout << "L(1) M(2) C(3) Go(0): ";
cin >> in;
while (in) {
if (in == 1)
roles[i++] = new Larry;
else if (in == 2)
roles[i++] = new Moe;
else
roles[i++] = new Curly;
cout << "L(1) M(2) C(3) Go(0): ";
cin >> in;
}
for (j=0; j < i; j++)
roles[j]->slapStick();
for (j=0; j < i; j++)
delete roles[j];
system( "pause" );
}
// L(1) M(2) C(3) Go(0): 1
// L(1) M(2) C(3) Go(0): 2
// L(1) M(2) C(3) Go(0): 3
// L(1) M(2) C(3) Go(0): 1
// L(1) M(2) C(3) Go(0): 0
// Larry: poke eyes
// Moe: slap head
// Curly: suffer abuse
// Larry: poke eyes
#include <iostream>
using namespace std;
class Stooge {
public:
virtual Stooge* clone() = 0;
virtual void slapStick() = 0;
};
class Factory {
public:
static Stooge* create( int i );
private:
static Stooge* prototypes_[4];
};
int main( void ) {
Stooge* roles[10];
int in, j, i = 0;
cout << "vlh L(1) M(2) C(3) Go(0): ";
cin >> in;
while (in) {
roles[i++] = Factory::create(in);
cout << "L(1) M(2) C(3) Go(0): ";
cin >> in;
}
for (j=0; j < i; j++)
roles[j]->slapStick();
for (j=0; j < i; j++)
delete roles[j];
system( "pause" );
}
class Larry : public Stooge {
public:
Stooge* clone() { return new Larry; }
void slapStick() {
cout << "Larry: poke eyes" << endl; }
};
class Moe : public Stooge {
public:
Stooge* clone() { return new Moe; }
void slapStick() {
cout << "Moe: slap head" << endl; }
};
class Curly : public Stooge {
public:
Stooge* clone() {return new Curly;}
void slapStick() {
cout << "Curly: suffer abuse" << endl; }
};
Stooge* Factory::prototypes_[] = { 0, new Larry, new Moe, new Curly };
Stooge* Factory::create( int i ) { return prototypes_[i]->clone(); }
// Purpose. Prototype design pattern demo
//
// Discussion. Image base class provides the mechanism for storing,
// finding, and cloning the prototype for all derived classes. Each
// derived class specifies a private static data member whose
// initialization "registers" a prototype of itself with the base class.
// When the client asks for a "clone" of a certain type, the base class
// finds the prototype and calls clone() on the correct derived class.
#include <iostream.h>
enum imageType { LSAT, SPOT };
class Image {
public:
virtual void draw() = 0;
static Image* findAndClone( imageType );
protected:
virtual imageType returnType() = 0;
virtual Image* clone() = 0;
// As each subclass of Image is declared, it registers its prototype
static void addPrototype( Image* image )
{ _prototypes[_nextSlot++] = image; }
private:
// addPrototype() saves each registered prototype here
static Image* _prototypes[10];
static int _nextSlot;
};
Image* Image::_prototypes[];
int Image::_nextSlot;
// Client calls this public static member function when it needs an instance
// of an Image subclass
Image* Image::findAndClone( imageType type )
{
for (int i=0; i < _nextSlot; i++)
if (_prototypes[i]->returnType() == type)
return _prototypes[i]->clone();
}
class LandSatImage : public Image {
public:
imageType returnType() { return LSAT; }
void draw() { cout << "LandSatImage::draw " << _id << endl; }
// When clone() is called, call the one-argument ctor with a dummy arg
Image* clone() { return new LandSatImage( 1 ); }
protected:
// This is only called from clone()
LandSatImage( int dummy ) { _id = _count++; }
private:
// Mechanism for initializing an Image subclass - this causes the
// default ctor to be called, which registers the subclass's prototype
static LandSatImage _landSatImage;
// This is only called when the private static data member is inited
LandSatImage() { addPrototype( this ); }
// Nominal "state" per instance mechanism
int _id;
static int _count;
};
// Register the subclass's prototype
LandSatImage LandSatImage::_landSatImage;
// Initialize the "state" per instance mechanism
int LandSatImage::_count = 1;
class SpotImage : public Image {
public:
imageType returnType() { return SPOT; }
void draw() { cout << "SpotImage::draw " << _id << endl; }
Image* clone() { return new SpotImage( 1 ); }
protected:
SpotImage( int dummy ) { _id = _count++; }
private:
SpotImage() { addPrototype( this ); }
static SpotImage _spotImage;
int _id;
static int _count;
};
SpotImage SpotImage::_spotImage;
int SpotImage::_count = 1;
// Simulated stream of creation requests
const int NUM_IMAGES = 8;
imageType input[NUM_IMAGES] =
{ LSAT, LSAT, LSAT, SPOT, LSAT, SPOT, SPOT, LSAT };
void main() {
Image* images[NUM_IMAGES];
// Given an image type, find the right prototype, and return a clone
for (int i=0; i < NUM_IMAGES; i++)
images[i] = Image::findAndClone( input[i] );
// Demonstrate that correct image objects have been cloned
for (i=0; i < NUM_IMAGES; i++)
images[i]->draw();
// Free the dynamic memory
for (i=0; i < NUM_IMAGES; i++)
delete images[i];
}
// LandSatImage::draw 1
// LandSatImage::draw 2
// LandSatImage::draw 3
// SpotImage::draw 1
// LandSatImage::draw 4
// SpotImage::draw 2
// SpotImage::draw 3
// LandSatImage::draw 5
// Purpose. Singleton // New design. "globalObj" is now a
// // private static data member of its
// Discussion. On the left, a global // own class. Global access is pro-
// object is architected to require // vided by the public static member
// lazy initialization (not inited un- // function inst(). And the lazy
// til it is needed). This requires // initialization code is encapsu-
// all users of the object to test and // lated in the inst() function.
// potentially allocate the pointer. // GlobalClass's ctor and dtor have
// Singleton suggests making the class // been made protected so that cli-
// itself responsible for creating, // ents cannot create more inst's
// maintaining, and providing global // or destroy the Singleton inst.
// access to its own single instance.
class GlobalClass {
#include <iostream.h> public:
int getValue() {
class GlobalClass { return value_; }
public: void setValue( int v ) {
GlobalClass( int v=0 ) { value_ = v; }
value_ = v; } static GlobalClass* inst() {
int getValue() { if ( ! globalObj_ )
return value_; } globalObj_ = new GlobalClass;
void setValue( int v ) { return globalObj_; }
value_ = v; } protected:
private: GlobalClass( int v=0 ) {
int value_; value_ = v; }
}; ~GlobalClass() { }
private:
// Initializing a global ptr to class int value_;
// GlobalClass static GlobalClass* globalObj_;
GlobalClass* globalObj = 0; };
void foo( void ) // Allocating and initializing
{ // GlobalClass's static data member
if ( ! globalObj ) // (the ptr, not a GlobalClass inst)
globalObj = new GlobalClass; GlobalClass*
globalObj->setValue( 1 ); GlobalClass::globalObj_ = 0;
cout << "foo: globalObj is " <<
globalObj->getValue() << endl; void foo( void )
} {
GlobalClass::inst()->setValue( 1 );
void bar( void ) cout << "foo: globalObj is " <<
{ GlobalClass::inst()->getValue()
if ( ! globalObj ) << endl;
globalObj = new GlobalClass; }
globalObj->setValue( 2 );
cout << "bar: globalObj is " << void bar( void )
globalObj->getValue() << endl; {
} GlobalClass::inst()->setValue( 2 );
cout << "bar: globalObj is " <<
void main( void ) GlobalClass::inst()->getValue()
{ << endl;
if ( ! globalObj ) }
globalObj = new GlobalClass;
cout << "main: globalObj is " << void main( void )
globalObj->getValue() << endl; {
foo(); cout << "main: globalObj is " <<
bar(); GlobalClass::inst()->getValue()
} << endl;
foo();
// main: globalObj is 0 bar();
// foo: globalObj is 1 }
// bar: globalObj is 2
// main: globalObj is 0
// foo: globalObj is 1
// bar: globalObj is 2
// Purpose. Singleton destroyer class GlobalClass;
//
// Discussion. Vlissides describes class SingDest {
// that Singletons can be cleaned-up public:
// by "wrapping" the ptr in a stack- SingDest( GlobalClass* s=0 ) {
// based static member of another sing_ = s; }
// class whose sole responsibility is ~SingDest();
// to have its destructor delete the void setSing( GlobalClass* s ) {
// Singleton's ptr. The Singleton sing_ = s; }
// destroyer is automatically cre- private:
// ated before main() is run, and GlobalClass* sing_;
// initially contains a null ptr. };
// The first time the inst() method
// is called, the destroyer is class GlobalClass {
// meaningfully initialized. public:
friend class SingDest;
#include <iostream.h> int getValue() { return value_; }
void setValue( int v ) {
class GlobalClass { value_ = v; }
public: static GlobalClass* inst() {
int getValue() { if ( ! globalObj_ ) {
return value_; } globalObj_ = new GlobalClass;
void setValue( int v ) { dest_.setSing( globalObj_ ); }
value_ = v; } return globalObj_; }
static GlobalClass* inst() { private:
if ( ! globalObj_ ) GlobalClass( int v=0 ) {
globalObj_ = new GlobalClass; cout << ":ctor: ";
return globalObj_; } value_ = v; }
protected: ~GlobalClass() {
GlobalClass( int v=0 ) { cout << ":dtor:" << endl; }
value_ = v; } int value_;
~GlobalClass() { } static GlobalClass* globalObj_;
private: static SingDest dest_;
int value_; };
static GlobalClass* globalObj_;
}; GlobalClass*
GlobalClass::globalObj_ = 0;
// Allocating and initializing SingDest GlobalClass::dest_;
// GlobalClass's static data member SingDest::~SingDest() { delete sing_; }
// (the ptr, not a GlobalClass inst)
GlobalClass* void foo( void ) {
GlobalClass::globalObj_ = 0; GlobalClass::inst()->setValue( 1 );
cout << "foo: globalObj is " <<
void foo( void ) { GlobalClass::inst()->getValue()
GlobalClass::inst()->setValue( 1 ); << endl;
cout << "foo: globalObj is " << }
GlobalClass::inst()->getValue() void bar( void ) {
<< endl; GlobalClass::inst()->setValue( 2 );
} cout << "bar: globalObj is " <<
void bar( void ) { GlobalClass::inst()->getValue()
GlobalClass::inst()->setValue( 2 ); << endl;
cout << "bar: globalObj is " << }
GlobalClass::inst()->getValue() void main( void ) {
<< endl; cout << "main: globalObj is " <<
} GlobalClass::inst()->getValue()
void main( void ) { << endl;
cout << "main: globalObj is " << foo();
GlobalClass::inst()->getValue() bar();
<< endl; cout << "main: end" << endl;
foo(); }
bar();
} // main: globalObj is :ctor: 0
// foo: globalObj is 1
// main: globalObj is 0 // bar: globalObj is 2
// foo: globalObj is 1 // main: end
// bar: globalObj is 2 // :dtor:
// Purpose. Singleton (Scott Meyers // New design. "globalObj" is now a
// approach) // static variable in the inst() ac-
// Discussion. On the left, a global // cessor method. The single inst-
// object is architected to require // ance is enforced by declaring the
// lazy initialization (not inited un- // ctor non-public. [The dtor must
// til it is needed). This requires // be public because of the static
// all users of the object to test and // variable instance.] Global
// potentially allocate the pointer. // access is provided by the static
// Singleton suggests making the class // inst() method. The object is al-
// itself responsible for creating, // located on first demand by C++,
// maintaining, and providing global // and it is de-allocated automati-
// access to its own single instance. // cally by C++.
#include <iostream.h> #include <iostream.h>
class GlobalClass { class GlobalClass {
public: public:
GlobalClass( int v=0 ) { int getValue() {
value_ = v; } return value_; }
int getValue() { void setValue( int v ) {
return value_; } value_ = v; }
void setValue( int v ) { static GlobalClass& inst() {
value_ = v; } static GlobalClass globalObj;
private: return globalObj; }
int value_; ~GlobalClass() {
}; cout << ":dtor:" << endl; }
protected:
// Initializing a global ptr to class GlobalClass( int v=0 ) {
// GlobalClass cout << ":ctor: ";
GlobalClass* globalObj = 0; value_ = v; }
private:
void foo( void ) int value_;
{ };
if ( ! globalObj )
globalObj = new GlobalClass; void foo( void )
globalObj->setValue( 1 ); {
cout << "foo: globalObj is " << GlobalClass::inst().setValue( 1 );
globalObj->getValue() << endl; cout << "foo: globalObj is " <<
} GlobalClass::inst().getValue()
<< endl;
void bar( void ) }
{
if ( ! globalObj ) void bar( void )
globalObj = new GlobalClass; {
globalObj->setValue( 2 ); GlobalClass::inst().setValue( 2 );
cout << "bar: globalObj is " << cout << "bar: globalObj is " <<
globalObj->getValue() << endl; GlobalClass::inst().getValue()
} << endl;
}
void main( void )
{ void main( void )
if ( ! globalObj ) {
globalObj = new GlobalClass; cout << "main: globalObj is " <<
cout << "main: globalObj is " << GlobalClass::inst().getValue()
globalObj->getValue() << endl; << endl;
foo(); foo();
bar(); bar();
} cout << "main: end" << endl;
}
// main: globalObj is 0
// foo: globalObj is 1 // main: globalObj is :ctor: 0
// bar: globalObj is 2 // foo: globalObj is 1
// bar: globalObj is 2
// main: end
// :dtor:
// Purpose. Singleton design pattern
// 1. Define a private static attribute in the "single instance" class
// 2. Define a public static accessor function in the class
// 3. Do "lazy initialization" (creation on demand) in the accessor function
// 4. Define all constructors to be protected or private
// 5. Clients may only use the accessor function to manipulate the Singleton
// 6. Inheritance can be supported, but static functions may not be overridden.
// The base class must be declared a friend of the derived class (in order
// to access the protected constructor).
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
class Number {
public:
static Number* instance(); // 2. Define a public static accessor func
static void setType( string t ) { type = t; delete inst; inst = 0;}
virtual void setValue( int in ) { value = in; }
virtual int getValue() { return value; }
protected:
int value;
Number() { cout << ":ctor: "; } // 4. Define all ctors to be protected
private:
static string type;
static Number* inst; // 1. Define a private static attribute
};
string Number::type = "decimal";
Number* Number::inst = 0;
class Octal : public Number { // 6. Inheritance can be supported
public:
friend class Number;
void setValue( int in ) {
char buf[10];
sprintf( buf, "%o", in );
sscanf( buf, "%d", &value );
}
protected:
Octal() { }
};
Number* Number::instance() {
if ( ! inst)
// 3. Do "lazy initialization" in the accessor function
if (type == "octal") inst = new Octal();
else inst = new Number();
return inst;
}
void main( void ) {
// Number myInstance; --- error: cannot access protected constructor
// 5. Clients may only use the accessor function to manipulate the Singleton
Number::instance()->setValue( 42 );
cout << "value is " << Number::instance()->getValue() << endl;
Number::setType( "octal" );
Number::instance()->setValue( 64 );
cout << "value is " << Number::instance()->getValue() << endl;
}
// :ctor: value is 42
// :ctor: value is 100
// Purpose. Adapter
//
// Discussion. The Adapter pattern
// discusses how to "wrap" the old in-
// terface of a legacy component, so
// that it can continue to contribute
// in a new system. It is about "im- #include <iostream.h>
// pedance matching" an old dog with #include <stdio.h>
// new tricks (to mix metaphors). On #include <time.h>
// the left, WimpyTime "hasa" in-
// stance of the legacy component, class ManlyTime {
// and delegates the "heavy lifting" public:
// to it. On the right, private char* getTime() {
// derivation is used to accomplish static char buf[30];
// the same result. time_t lt;
tm* ltStruct;
class ManlyTime { time( < );
public: ltStruct = localtime(<);
char* getTime() { strftime( buf, 30, "%H%M",
static char buf[30]; ltStruct );
time_t lt; return buf;
tm* ltStruct; }
time( < ); };
ltStruct = localtime(<);
strftime( buf, 30, "%H%M", class WimpyTime :
ltStruct ); private ManlyTime {
return buf; public:
} char* getTime() {
}; static char buf[30];
char *ptr, mi[3], am[3];
class WimpyTime { int hr;
public: ptr = ManlyTime::getTime();
char* getTime() { cout << "old interface time is "
static char buf[30]; << ptr << endl;
char *ptr, mi[3], am[3]; strcpy( mi, &(ptr[2]) );
int hr; ptr[2] = '\0';
ptr = imp_.getTime(); sscanf( ptr, "%d", &hr );
cout << "old interface time is " strcpy( am, "AM" );
<< ptr << endl; if (hr > 12) {
strcpy( mi, &(ptr[2]) ); hr -= 12;
ptr[2] = '\0'; strcpy( am, "PM" ); }
sscanf( ptr, "%d", &hr ); sprintf( buf, "%d:%s %s",
strcpy( am, "AM" ); hr, mi, am );
if (hr > 12) { return buf;
hr -= 12; }
strcpy( am, "PM" ); } };
sprintf( buf, "%d:%s %s",
hr, mi, am ); void main( void )
return buf; {
} WimpyTime newT;
private: char* ptr;
ManlyTime imp_; ptr = newT.getTime();
}; cout << "new interface time is "
<< ptr << endl;
void main( void ) }
{
WimpyTime newT; // old interface time is 1721
char* ptr; // new interface time is 5:21 PM
ptr = newT.getTime();
cout << "new interface time is "
<< ptr << endl;
}
// old interface time is 1709
// new interface time is 5:09 PM
// Purpose. Adapter design pattern demo
//
// Discussion. LegacyRectangle's interface is not compatible with the
// system that would like to reuse it. An abstract base class is created
// that specifies the desired interface. An "adapter" class is defined
// that publicly inherits the interface of the abstract class, and
// privately inherits the implementation of the legacy component. This
// adapter class "maps" or "impedance matches" the new interface to the
// old implementation.
#include <iostream.h>
typedef int Coordinate;
typedef int Dimension;
/////////////////////////// Desired interface ///////////////////////////
class Rectangle {
public:
virtual void draw() = 0;
};
/////////////////////////// Legacy component ///////////////////////////
class LegacyRectangle {
public:
LegacyRectangle( Coordinate x1, Coordinate y1,
Coordinate x2, Coordinate y2 ) {
x1_ = x1; y1_ = y1; x2_ = x2; y2_ = y2;
cout << "LegacyRectangle: create. (" << x1_ << "," << y1_
<< ") => (" << x2_ << "," << y2_ << ")" << endl; }
void oldDraw() {
cout << "LegacyRectangle: oldDraw. (" << x1_ << "," << y1_
<< ") => (" << x2_ << "," << y2_ << ")" << endl; }
private:
Coordinate x1_;
Coordinate y1_;
Coordinate x2_;
Coordinate y2_;
};
/////////////////////////// Adapter wrapper ///////////////////////////
class RectangleAdapter : public Rectangle, private LegacyRectangle {
public:
RectangleAdapter( Coordinate x, Coordinate y, Dimension w, Dimension h )
: LegacyRectangle( x, y, x+w, y+h ) {
cout << "RectangleAdapter: create. (" << x << "," << y
<< "), width = " << w << ", height = " << h << endl; }
virtual void draw() {
cout << "RectangleAdapter: draw." << endl;
oldDraw(); }
};
void main() {
Rectangle* r = new RectangleAdapter( 120, 200, 60, 40 );
r->draw();
}
// LegacyRectangle: create. (120,200) => (180,240)
// RectangleAdapter: create. (120,200), width = 60, height = 40
// RectangleAdapter: draw.
// LegacyRectangle: oldDraw. (120,200) => (180,240)
// Purpose. Adapter design pattern (External Polymorphism demo)
// 1. Specify the new desired interface
// 2. Design a "wrapper" class that can "impedance match" the old to the new
// 3. The client uses (is coupled to) the new interface
// 4. The adapter/wrapper "maps" to the legacy implementation
#include <iostream.h>
class ExecuteInterface { public: // 1. Specify the new i/f
virtual ~ExecuteInterface() { }
virtual void execute() = 0;
};
template <class TYPE> // 2. Design a "wrapper" or
class ExecuteAdapter : public ExecuteInterface { // "adapter" class
public:
ExecuteAdapter( TYPE* o, void (TYPE::*m)() ) { object = o; method =m; }
~ExecuteAdapter() { delete object; }
// 4. The adapter/wrapper "maps" the new to the legacy implementation
void execute() /* the new */ { (object->*method)(); }
private:
TYPE* object; // ptr-to-object attribute
void (TYPE::*method)(); /* the old */ // ptr-to-member-function
}; // attribute
// The old: three totally incompatible classes // no common base class,
class Fea { public: // no hope of polymorphism
~Fea() { cout << "Fea::dtor" << endl; }
void doThis() { cout << "Fea::doThis()" << endl; }
};
class Feye { public:
~Feye() { cout << "Feye::dtor" << endl; }
void doThat() { cout << "Feye::doThat()" << endl; }
};
class Pheau { public:
~Pheau() { cout << "Pheau::dtor" << endl; }
void doTheOther() { cout << "Pheau::doTheOther()" << endl; }
};
/* the new is returned */ ExecuteInterface** initialize() {
ExecuteInterface** array = new ExecuteInterface*[3]; /* the old is below */
array[0] = new ExecuteAdapter<Fea>( new Fea(), &Fea::doThis );
array[1] = new ExecuteAdapter<Feye>( new Feye(), &Feye::doThat );
array[2] = new ExecuteAdapter<Pheau>( new Pheau(), &Pheau::doTheOther );
return array;
}
void main( void ) {
ExecuteInterface** objects = initialize();
for (int i=0; i < 3; i++) objects[i]->execute(); // 3. Client uses the new
// (polymporphism)
for (i=0; i < 3; i++) delete objects[i];
delete objects;
}
// Fea::doThis()
// Feye::doThat()
// Pheau::doTheOther()
// Fea::dtor
// Feye::dtor
// Pheau::dtor
// Purpose. Bridge class DateImp;
//
// Discussion. Even though Date has class Date {
// a clean interface and a well encap- public:
// sulated implementation, the client Date( int y, int m, int d );
// still has to recompile if the class ~Date();
// architect changes his/her mind. void output();
// Instead, create a wrapper (or inter- static void setImp( char* t ) {
// face) class that contains and dele- strcpy( impType_, t ); }
// gates to a body (or implementation) private:
// class. Client can now specify at DateImp* rep_;
// run-time exactly what s/he wants. static char impType_[10];
};
#include <iostream.h> char Date::impType_[] = "Ok";
#include <stdio.h>
class DateImp { public:
class Date { virtual void output() = 0;
};
public:
Date( int y, int m, int d ); class DateOk : public DateImp {
void output(); public:
DateOk( int y, int m, int d );
private: void output();
private:
#ifdef OK int year_, month_, day_;
int year_, month_, day_; };
#endif
class DateAA : public DateImp {
#ifdef AA public:
int toJulian(int,int,int); DateAA( int y, int m, int d );
char* fromJulian(void); void output();
int julian_; private:
int year_; int toJulian(int,int,int);
static int dayTable_[2][13]; char* fromJulian(void);
#endif int julian_;
int year_;
}; static int dayTable_[2][13];
};
#ifdef OK
void Date::output() { Date::Date( int y, int m, int d ) {
char buf[20]; if ( ! strcmp( impType_, "Ok" ))
int year = year_ - (year_/100*100); rep_ = new DateOk( y, m, d );
sprintf( buf, "%02d%02d%02d", else
year, month_, day_ ); rep_ = new DateAA( y, m, d );
cout << buf << " "; } }
#endif Date::~Date() { delete rep_; }
void Date::output() { rep_->output(); }
#ifdef AA
void Date::output() { #include "bridge2.inc"
cout << fromJulian() << " "; }
#endif void main( void )
{
#include "bridge1.inc" Date d1( 1996, 2, 29 );
Date d2( 1996, 2, 30 );
void main( void ) Date::setImp( "AA" );
{ Date d3( 1996, 2, 29 );
Date d1( 1996, 2, 29 ); Date d4( 1996, 2, 30 );
Date d2( 1996, 2, 30 ); d1.output(); d2.output();
d1.output(); cout << endl;
d2.output(); d3.output(); d4.output();
cout << endl; cout << endl;
} }
// 960229 960230 // 960229 960230
// 960229 960301 // 960229 960301
// Purpose. Bridge design pattern demo
//
// Discussion. The motivation is to decouple the Time interface from the
// Time implementation, while still allowing the abstraction and the
// realization to each be modelled with their own inheritance hierarchy.
// The implementation classes below are straight-forward. The interface
// classes are a little more subtle. Routinely, a Bridge pattern
// interface hierarchy "hasa" implementation class. Here the interface
// base class "hasa" a pointer to the implementation base class, and each
// class in the interface hierarchy is responsible for populating the base
// class pointer with the correct concrete implementation class. Then all
// requests from the client are simply delegated by the interface class to
// the encapsulated implementation class.
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
class TimeImp {
public:
TimeImp( int hr, int min ) {
hr_ = hr; min_ = min; }
virtual void tell() {
cout << "time is " << setw(2) << setfill(48) << hr_ << min_ << endl; }
protected:
int hr_, min_;
};
class CivilianTimeImp : public TimeImp {
public:
CivilianTimeImp( int hr, int min, int pm ) : TimeImp( hr, min ) {
if (pm)
strcpy( whichM_, " PM" );
else
strcpy( whichM_, " AM" ); }
/* virtual */ void tell() {
cout << "time is " << hr_ << ":" << min_ << whichM_ << endl; }
protected:
char whichM_[4];
};
class ZuluTimeImp : public TimeImp {
public:
ZuluTimeImp( int hr, int min, int zone ) : TimeImp( hr, min ) {
if (zone == 5)
strcpy( zone_, " Eastern Standard Time" );
else if (zone == 6)
strcpy( zone_, " Central Standard Time" ); }
/* virtual */ void tell() {
cout << "time is " << setw(2) << setfill(48) << hr_ << min_
<< zone_ << endl; }
protected:
char zone_[30];
};
class Time {
public:
Time() { }
Time( int hr, int min ) {
imp_ = new TimeImp( hr, min ); }
virtual void tell() {
imp_->tell(); }
protected:
TimeImp* imp_;
};
class CivilianTime : public Time {
public:
CivilianTime( int hr, int min, int pm ) {
imp_ = new CivilianTimeImp( hr, min, pm ); }
};
class ZuluTime : public Time {
public:
ZuluTime( int hr, int min, int zone ) {
imp_ = new ZuluTimeImp( hr, min, zone ); }
};
void main() {
Time* times[3];
times[0] = new Time( 14, 30 );
times[1] = new CivilianTime( 2, 30, 1 );
times[2] = new ZuluTime( 14, 30, 6 );
for (int i=0; i < 3; i++)
times[i]->tell();
}
// time is 1430
// time is 2:30 PM
// time is 1430 Central Standard Time
// Purpose. Composite // Strategy. Use recursive composition
// to create a heterogeneous aggregate
#include <string.h> // that can be treated homogeneously.
enum NodeType { FileT, DirT }; //
int g_indent = 0; // Benefit. No more type checking and
// type casting (coupling between Dir
class File { // and File is gone, Dir is only
public: // coupled to abstract base class)
File( char* n ) { type_ = FileT;
strcpy( name_, n ); } class AbsFile {
NodeType getType() { return type_; } public:
void ls() { virtual void ls() = 0;
for (int i=0; i < g_indent; i++) protected:
cout << ' '; char name_[20];
cout << name_ << endl; } static int indent_;
private: };
NodeType type_; int AbsFile::indent_ = 0;
char name_[20];
}; class File: public AbsFile {
public:
class Dir { File( char* n ) {
public: strcpy( name_, n ); }
Dir( char* n ) { type_ = DirT; void ls() {
strcpy( name_, n ); total_ = 0; } for (int i=0; i < indent_; i++)
NodeType getType() { return type_; } cout << ' ';
void add( File* f ) { cout << name_ << endl; }
files_[total_++] = f; };
}
void ls() { class Dir : public AbsFile {
for (int i=0; i < g_indent; i++) public:
cout << ' '; Dir( char* n ) {
cout << name_ << ":" << endl; strcpy( name_, n ); total_ = 0; }
g_indent += 3; void add( AbsFile* f ) {
for (int i=0; i < total_; i++) files_[total_++] = f; }
if (files_[i]->getType() void ls() {
== DirT) for (int i=0; i < indent_; i++)
((Dir*) files_[i])->ls(); cout << ' ';
else cout << name_ << ":" << endl;
files_[i]->ls(); indent_ += 3;
g_indent -= 3; } for (int i=0; i < total_; i++)
private: files_[i]->ls();
NodeType type_; indent_ -= 3; }
char name_[20]; private:
File* files_[10]; AbsFile* files_[10];
int total_; int total_;
}; };
void main( void ) void main( void )
{ {
Dir one("1"), two("2"), thr("3"); Dir one("1"), two("2"), thr("3");
File a("a"), b("b"), c("c"), File a("a"), b("b"), c("c"),
d("d"), e("e"); d("d"), e("e");
one.add( &a ); one.add( &a );
one.add( (File*) &two ); one.add( &two );
one.add( &b ); one.add( &b );
two.add( &c ); two.add( &c );
two.add( &d ); two.add( &d );
two.add( (File*) &thr ); two.add( &thr );
thr.add( &e ); thr.add( &e );
one.ls(); one.ls();
} }
// 1: // d // 1: // d
// a // 3: // a // 3:
// 2: // e // 2: // e
// c // b // c // b
// Purpose. Composite design pattern
//
// 1. Identify the scalar/primitive classes and vector/container classes
// 2. Create an "interface" (lowest common denominator) that can make all
// concrete classes "interchangeable"
// 3. All concrete classes declare an "is a" relationship to the interface
// 4. All "container" classes couple themselves to the interface (recursive
// composition, Composite "has a" set of children up the "is a" hierarchy)
// 5. "Container" classes use polymorphism as they delegate to their children
#include <iostream>
#include <vector>
using namespace std;
// 2. Create an "interface" (lowest common denominator)
class Component { public: virtual void traverse() = 0; };
class Leaf : public Component { // 1. Scalar class 3. "isa" relationship
int value;
public:
Leaf( int val ) { value = val; }
void traverse() { cout << value << ' '; }
};
class Composite : public Component { // 1. Vector class 3. "isa" relationship
vector<Component*> children; // 4. "container" coupled to the interface
public:
// 4. "container" class coupled to the interface
void add( Component* ele ) { children.push_back( ele ); }
void traverse() {
for (int i=0; i < children.size(); i++)
// 5. Use polymorphism to delegate to children
children[i]->traverse();
} };
void main( void ) {
Composite containers[4];
for (int i=0; i < 4; i++)
for (int j=0; j < 3; j++)
containers[i].add( new Leaf( i * 3 + j ) );
for (i=1; i < 4; i++)
containers[0].add( &(containers[i]) );
for (i=0; i < 4; i++) {
containers[i].traverse();
cout << endl;
} }
// 0 1 2 3 4 5 6 7 8 9 10 11
// 3 4 5
// 6 7 8
// 9 10 11
// Purpose. Composite design pattern - multiple container classes
#include <iostream>
#include <vector>
using namespace std;
class Component { public: virtual void traverse() = 0; };
class Primitive : public Component {
int value;
public:
Primitive( int val ) { value = val; }
void traverse() { cout << value << " "; }
};
class Composite : public Component {
vector<Component*> children;
int value;
public:
Composite( int val ) { value = val; }
void add( Component* c ) { children.push_back( c ); }
void traverse() {
cout << value << " ";
for (int i=0; i < children.size(); i++)
children[i]->traverse();
} };
class Row : public Composite { public: // Two different kinds of "con-
Row( int val ) : Composite( val ) { } // tainer" classes. Most of the
void traverse() { // "meat" is in the Composite
cout << "Row"; // base class.
Composite::traverse();
} };
class Column : public Composite { public:
Column( int val ) : Composite( val ) { }
void traverse() {
cout << "Col";
Composite::traverse();
} };
void main( void ) {
Row first( 1 ); // Row1
Column second( 2 ); // |
Column third( 3 ); // +-- Col2
Row fourth( 4 ); // | |
Row fifth( 5 ); // | +-- 7
first.add( &second ); // +-- Col3
first.add( &third ); // | |
third.add( &fourth ); // | +-- Row4
third.add( &fifth ); // | | |
first.add( &Primitive( 6 ) ); // | | +-- 9
second.add( &Primitive( 7 ) ); // | +-- Row5
third.add( &Primitive( 8 ) ); // | | |
fourth.add( &Primitive( 9 ) ); // | | +-- 10
fifth.add( &Primitive(10 ) ); // | +-- 8
first.traverse(); cout << '\n'; // +-- 6
}
// Row1 Col2 7 Col3 Row4 9 Row5 10 8 6
// Purpose. Composite and Prototype - lightweight persistence
#pragma warning( disable : 4786 )
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <fstream>
using namespace std;
class Component { public:
virtual ~Component() { }
virtual void traverse() = 0;
virtual Component* clone() = 0;
virtual void initialize( ifstream& ) = 0;
};
namespace Factory {
map<string,Component*> hash;
void add( string s, Component* c ) { hash[s] = c; }
Component* makeComponent( string name ) { return hash[name]->clone(); }
}
class Leaf : public Component {
string value;
public:
~Leaf() { cout << 'd' << value << ' '; }
/*virtual*/ void traverse() { cout << value << ' '; }
/*virtual*/ Component* clone() { return new Leaf(); }
/*virtual*/ void initialize( ifstream& is ) { is >> value; }
};
class Composite : public Component {
vector<Component*> children;
string value;
public:
~Composite() {
cout << 'd' << value << ' ';
for (int i=0; i < children.size(); i++)
delete children[i];
}
void add( Component* c ) { children.push_back( c ); }
/*virtual*/ void traverse() {
cout << value << ' ';
for (int i=0; i < children.size(); i++)
children[i]->traverse();
}
/*virtual*/ Component* clone() { return new Composite(); }
/*virtual*/ void initialize( ifstream& is ) {
is >> value;
string str, delim( "/"+value );
is >> str;
while (str != delim) {
add( Factory::makeComponent( str ) );
children[children.size()-1]->initialize( is );
is >> str;
} } };
void main( void ) {
Factory::add( "comp", new Composite() );
Factory::add( "leaf", new Leaf() );
ifstream is( "compositeCreate.txt" );
string str;
is >> str;
Component* root = Factory::makeComponent( str );
root->initialize( is );
root->traverse(); cout << '\n';
delete root; cout << '\n';
}
/***
comp a leaf 1 comp b comp d leaf 8 leaf 9 /d leaf 4 comp e leaf 10
leaf 11 leaf 12 /e leaf 2 comp c leaf 5 leaf 6 leaf 7 /c /b leaf 3 /a
***/
// a 1 b d 8 9 4 e 10 11 12 2 c 5 6 7 3
// da d1 db dd d8 d9 d4 de d10 d11 d12 d2 dc d5 d6 d7 d3
// Purpose. Decorator design pattern
// 1. Create a "lowest common denominator" that makes classes interchangeable
// 2. Create a second level base class for optional functionality
// 3. "Core" class and "Decorator" class declare an "isa" relationship
// 4. Decorator class "hasa" instance of the "lowest common denominator"
// 5. Decorator class delegates to the "hasa" object
// 6. Create a Decorator derived class for each optional embellishment
// 7. Decorator derived classes delegate to base class AND add extra stuf
// 8. Client has the responsibility to compose desired configurations
#include <iostream>
using namespace std;
class Widget { public: virtual void draw() = 0; }; // 1. "lowest common denom"
class TextField : public Widget { // 3. "Core" class & "isa"
int width, height;
public:
TextField( int w, int h ) { width = w; height = h; }
/*virtual*/ void draw() { cout << "TextField: " << width << ", " << height << '\n'; }
};
// 2. 2nd level base class
class Decorator : public Widget { // 3. "isa" relationship
Widget* wid; // 4. "hasa" relationship
public:
Decorator( Widget* w ) { wid = w; }
/*virtual*/ void draw() { wid->draw(); } // 5. Delegation
};
class BorderDecorator : public Decorator { public: // 6. Optional embellishment
BorderDecorator( Widget* w ) : Decorator( w ) { }
/*virtual*/ void draw() {
Decorator::draw(); // 7. Delegate to base class
cout << " BorderDecorator" << '\n'; // and add extra stuff
} };
class ScrollDecorator : public Decorator { public: // 6. Optional embellishment
ScrollDecorator( Widget* w ) : Decorator( w ) { }
/*virtual*/ void draw() {
Decorator::draw(); // 7. Delegate to base class
cout << " ScrollDecorator" << '\n'; // and add extra stuff
} };
void main( void ) {
// 8. Client has the responsibility to compose desired configurations
Widget* aWidget = new BorderDecorator(
new BorderDecorator(
new ScrollDecorator(
new TextField( 80, 24 ))));
aWidget->draw();
}
// TextField: 80, 24
// ScrollDecorator
// BorderDecorator
// BorderDecorator
// Purpose. Inheritance run amok
#include <iostream>
using namespace std;
class A { public:
virtual void doIt() { cout << 'A'; }
};
class AwithX : public A {
void doX() { cout << 'X'; }
public:
/*virtual*/ void doIt() {
A::doIt();
doX();
} };
class AwithY : public A {
protected:
void doY() { cout << 'Y'; }
public:
/*virtual*/ void doIt() {
A::doIt();
doY();
} };
class AwithZ : public A {
protected:
void doZ() { cout << 'Z'; }
public:
/*virtual*/ void doIt() {
A::doIt();
doZ();
} };
class AwithXY : public AwithX, public AwithY { public:
/*virtual*/ void doIt() {
AwithX::doIt();
AwithY::doY();
} };
class AwithXYZ : public AwithX, public AwithY, public AwithZ { public:
/*virtual*/ void doIt() {
AwithX::doIt();
AwithY::doY();
AwithZ::doZ();
} };
void main( void ) {
AwithX anX;
AwithXY anXY;
AwithXYZ anXYZ;
anX.doIt(); cout << '\n';
anXY.doIt(); cout << '\n';
anXYZ.doIt(); cout << '\n';
}
// AX
// AXY
// AXYZ
// Purpose. Replacing inheritance with wrapping-delegation
//
// Discussion. Use aggregation instead of inheritance to implement
// embellishments to a "core" object. Client can dynamically compose
// permutations, instead of the architect statically wielding multiple
// inheritance.
#include <iostream>
using namespace std;
class I { public:
virtual ~I() { }
virtual void doIt() = 0;
};
class A : public I { public:
~A() { cout << "A dtor" << '\n'; }
/*virtual*/ void doIt() { cout << 'A'; }
};
class D : public I {
I* wrappee;
public:
D( I* inner ) { wrappee = inner; }
~D() { delete wrappee; }
/*virtual*/ void doIt() { wrappee->doIt(); }
};
class X : public D { public:
X( I* core ) : D(core) { }
~X() { cout << "X dtor" << " "; }
/*virtual*/ void doIt() { D::doIt(); cout << 'X'; }
};
class Y : public D { public:
Y( I* core ) : D(core) { }
~Y() { cout << "Y dtor" << " "; }
/*virtual*/ void doIt() { D::doIt(); cout << 'Y'; }
};
class Z : public D { public:
Z( I* core ) : D(core) { }
~Z() { cout << "Z dtor" << " "; }
/*virtual*/ void doIt() { D::doIt(); cout << 'Z'; }
};
void main( void ) {
I* anX = new X( new A );
I* anXY = new Y( new X( new A ) );
I* anXYZ = new Z( new Y( new X( new A ) ) );
anX->doIt(); cout << '\n';
anXY->doIt(); cout << '\n';
anXYZ->doIt(); cout << '\n';
delete anX; delete anXY; delete anXYZ;
}
// AX
// AXY
// AXYZ
// X dtor A dtor
// Y dtor X dtor A dtor
// Z dtor Y dtor X dtor A dtor
// Purpose. Decorator - encoding and decoding layers of header/packet/trailer
#include <iostream>
#include <string>
using namespace std;
class Interface { public:
virtual ~Interface() { }
virtual void write( string& ) = 0;
virtual void read( string& ) = 0;
};
class Core : public Interface { public:
~Core() { cout << "dtor-Core\n"; }
/*virtual*/ void write( string& b ) { b += "MESSAGE|"; }
/*virtual*/ void read( string& );
};
class Decorator : public Interface {
Interface* inner;
public:
Decorator( Interface* c ) { inner = c; }
~Decorator() { delete inner; }
/*virtual*/ void write( string& b ) { inner->write( b ); }
/*virtual*/ void read( string& b ) { inner->read( b ); }
};
class Wrapper : public Decorator {
string forward, backward;
public:
Wrapper( Interface* c, string str ) : Decorator(c) {
forward = str;
string::reverse_iterator it;
it = str.rbegin();
for ( ; it != str.rend(); ++it)
backward += *it;
}
~Wrapper() { cout << "dtor-" << forward << " "; }
void write( string& );
void read( string& );
};
void main( void ) {
Interface* object = new Wrapper( new Wrapper( new Wrapper(
new Core(), "123" ), "abc" ), "987" );
string buf;
object->write( buf );
cout << "main: " << buf << endl;
object->read( buf );
delete object;
}
// main: 987]abc]123]MESSAGE|321]cba]789]
// Wrapper: 987
// Wrapper: abc
// Wrapper: 123
// Core: MESSAGE
// Wrapper: 321
// Wrapper: cba
// Wrapper: 789
// dtor-987 dtor-abc dtor-123 dtor-Core
void Core::read(string& b) {
int num = b.find_first_of( '|' );
cout << "Core: " << b.substr(0,num) << '\n';
b = b.substr(num+1);
}
void Wrapper::write( string& b ) {
b += forward + "]";
Decorator::write( b );
b += backward + "]";
}
void Wrapper::read( string& b ) {
int num = b.find_first_of( ']' );
cout << "Wrapper: " << b.substr(0,num) << '\n';
b = b.substr(num+1);
Decorator::read( b );
num = b.find_first_of( ']' );
cout << "Wrapper: " << b.substr(0,num) << '\n';
b = b.substr(num+1);
}
// Purpose. Facade #include <iostream.h>
// #include <string.h>
// Discussion. Class Compute models #define sl strlen
// a decimal digit adder module. An
// entire "subsystem" can be configur- class Compute {
// ed by linking as many of these public:
// modules as the desired precision char add( char a, char b, int& c ) {
// requires. The "subsystem" being int result = a + b + c - 96;
// modeled in main() is complex and c = 0;
// burdensome to use. Wrapping this if (result > 9) {
// subsystem inside of a Facade that result -= 10;
// exports a simple interface is c = 1;
// desirable. }
return result + 48;
#include <iostream.h> }
#include <string.h> };
#define sl strlen
class Facade {
class Compute { public:
public: char* add( char* a, char* b ) {
char add( char a, char b, int& c) { int cary = 0, i = 0;
int result = a + b + c - 96; char c, d;
c = 0; if ((sl(a) > 1) && (sl(b) > 1)) {
if (result > 9) { c = ones.add( a[1], b[1], cary );
result -= 10; d = tens.add( a[0], b[0], cary );
c = 1; } else if (sl(a) > 1) {
} c = ones.add( a[1], b[0], cary );
return result + 48; d = tens.add( a[0], '0', cary );
} } else if (sl(b) > 1) {
}; c = ones.add( b[1], a[0], cary );
d = tens.add( b[0], '0', cary );
void main( void ) { } else {
Compute tens, ones; c = tens.add( a[0], b[0], cary );
char a[9], b[9], c, d; d = 'x';
int cary; }
while (1) { if (cary) ans[i++] = '1';
cout << "Enter 2 nums: "; if (d != 'x') ans[i++] = d;
cin >> a >> b; ans[i++] = c;
cout << " sum is "; ans[i] = '\0';
cary = 0; return ans;
if ((sl(a) > 1) && (sl(b) > 1)) { }
c = ones.add( a[1], b[1], cary); private:
d = tens.add( a[0], b[0], cary); Compute tens, ones;
} else if (sl(a) > 1) { char ans[9];
c = ones.add( a[1], b[0], cary); };
d = tens.add( a[0], '0', cary);
} else if (sl(b) > 1) { void main( void ) {
c = ones.add( b[1], a[0], cary); Facade f;
d = tens.add( b[0], '0', cary); char a[9], b[9];
} else { while (1) {
c = tens.add( a[0], b[0], cary); cout << "Enter 2 nums: ";
d = 'x'; cin >> a >> b;
} cout <<" sum is "<< f.add(a,b)
if (cary) cout << '1'; << endl;
if (d != 'x') cout << d; } }
cout << c << endl;
} } // Enter 2 nums: 9 13
// sum is 22
// Enter 2 nums: 99 99 // Enter 2 nums: 19 8
// sum is 198 // sum is 27
// Enter 2 nums: 38 83 // Enter 2 nums: 3 99
// sum is 121 // sum is 102
// Enter 2 nums: 5 6
// sum is 11
// Purpose. Facade design pattern demo.
//
// Discussion. Structuring a system into subsystems helps reduce
// complexity. A common design goal is to minimize the communication and
// dependencies between subsystems. One way to achieve this goal is to
// introduce a "facade" object that provides a single, simplified
// interface to the many, potentially complex, individual interfaces
// within the subsystem. In this example, the "subsystem" for responding
// to a networking service request has been modeled, and a facade
// (FacilitiesFacade) interposed. The facade "hides" the twisted and
// bizarre choreography necessary to satisfy even the most basic of
// requests. All the user of the facade object has to do is make one or
// two phone calls a week for 5 months, and a completed service request
// results.
#include <iostream.h>
class MisDepartment {
public:
void submitNetworkRequest() { _state = 0; }
bool checkOnStatus() {
_state++;
if (_state == Complete)
return 1;
return 0; }
private:
enum States {Received, DenyAllKnowledge, ReferClientToFacilities,
FacilitiesHasNotSentPaperwork, ElectricianIsNotDone,
ElectricianDidItWrong, DispatchTechnician, SignedOff, DoesNotWork,
FixElectriciansWiring, Complete};
int _state;
};
class ElectricianUnion {
public:
void submitNetworkRequest() { _state = 0; }
bool checkOnStatus() {
_state++;
if (_state == Complete)
return 1;
return 0; }
private:
enum States {Received, RejectTheForm, SizeTheJob, SmokeAndJokeBreak,
WaitForAuthorization, DoTheWrongJob, BlameTheEngineer, WaitToPunchOut,
DoHalfAJob, ComplainToEngineer, GetClarification, CompleteTheJob,
TurnInThePaperwork, Complete};
int _state;
};
class FacilitiesDepartment {
public:
void submitNetworkRequest() { _state = 0; }
bool checkOnStatus() {
_state++;
if (_state == Complete)
return 1;
return 0; }
private:
enum States {Received, AssignToEngineer, EngineerResearches,
RequestIsNotPossible, EngineerLeavesCompany, AssignToNewEngineer,
NewEngineerResearches, ReassignEngineer, EngineerReturns,
EngineerResearchesAgain, EngineerFillsOutPaperWork, Complete};
int _state;
};
class FacilitiesFacade {
public:
FacilitiesFacade() { _count = 0; }
void submitNetworkRequest() { _state = 0; }
bool checkOnStatus() {
_count++;
/* Job request has just been received */
if (_state == Received) {
_state++;
/* Forward the job request to the engineer */
_engineer.submitNetworkRequest();
cout << "submitted to Facilities - " << _count
<< " phone calls so far" << endl; }
else if (_state == SubmitToEngineer) {
/* If engineer is complete, forward to electrician */
if (_engineer.checkOnStatus()) {
_state++;
_electrician.submitNetworkRequest();
cout << "submitted to Electrician - " << _count
<< " phone calls so far" << endl; } }
else if (_state == SubmitToElectrician) {
/* If electrician is complete, forward to technician */
if (_electrician.checkOnStatus()) {
_state++;
_technician.submitNetworkRequest();
cout << "submitted to MIS - " << _count
<< " phone calls so far" << endl; } }
else if (_state == SubmitToTechnician) {
/* If technician is complete, job is done */
if (_technician.checkOnStatus())
return 1; }
/* The job is not entirely complete */
return 0; }
int getNumberOfCalls() { return _count; }
private:
enum States {Received, SubmitToEngineer, SubmitToElectrician,
SubmitToTechnician};
int _state;
int _count;
FacilitiesDepartment _engineer;
ElectricianUnion _electrician;
MisDepartment _technician;
};
void main() {
FacilitiesFacade facilities;
facilities.submitNetworkRequest();
/* Keep checking until job is complete */
while ( ! facilities.checkOnStatus())
;
cout << "job completed after only " << facilities.getNumberOfCalls()
<< " phone calls" << endl;
}
// submitted to Facilities - 1 phone calls so far
// submitted to Electrician - 12 phone calls so far
// submitted to MIS - 25 phone calls so far
// job completed after only 35 phone calls
抽象工厂: 提供一个接口创建相关和依赖对象家族而不用说明他们的具体类
尝试维护在多个平台上的可移植性通常需要许多预编译条件.工厂模式建议定义一个创建服务接口在工厂基类,并且完美每个平台在各自工厂继承类
#include <iostream.h>
class Widget { public:
virtual void draw() = 0;
};
class MotifBtn : public Widget {
public:
void draw() { cout << "MotifBtn" << endl; }
};
class WindowsBtn : public Widget {
public:
void draw() { cout << "WindowsBtn" << endl; }
};
void doThisWindow() {
// create window, attach btn
#ifdef MOTIF
Widget* w = new MotifBtn;
#else // WINDOWS
Widget* w = new WindowsBtn;
#endif
w->draw(); }
void doThatWindow() {
// create window, attach btn
#ifdef MOTIF
Widget* w = new MotifBtn;
#else // WINDOWS
Widget* w = new WindowsBtn;
#endif
w->draw(); }
void main( void )
{
// create window, attach btn
#ifdef MOTIF
Widget* w = new MotifBtn;
#else // WINDOWS
Widget* w = new WindowsBtn;
#endif
w->draw();
doThisWindow();
doThatWindow();
}
// WindowsBtn
// WindowsBtn
// WindowsBtn
#include <iostream.h>
class Widget { public:
virtual void draw() = 0;
};
class MotifBtn : public Widget {
public:
void draw() { cout << "MotifBtn" << endl; }
};
class WindowsBtn : public Widget {
public:
void draw() { cout << "WindowsBtn" << endl; }
};
class Factory { public: virtual Widget* createBtn() = 0;
};
class MotifFactory : public Factory {
public:
Widget* createBtn() { return new MotifBtn; }
};
class WindowsFactory : public Factory {
public:
Widget* createBtn() { return new WindowsBtn; }
};
Factory* factory;
void doThisWindow() {
// create window, attach btn
Widget* w = factory->createBtn();
w->draw(); }
void doThatWindow() {
// create window, attach btn
Widget* w = factory->createBtn();
w->draw(); }
void main( void )
{
#ifdef MOTIF
factory = new MotifFactory;
#else // WINDOWS
factory = new WindowsFactory;
#endif
// create window, attach btn
Widget* w = factory->createBtn();
w->draw();
doThisWindow();
doThatWindow();
}
// MotifBtn
// MotifBtn
// MotifBtn
// Purpose. Abstract Factory #include <iostream.h>
//
// Discussion. Trying to maintain class Widget { public:
// portability across multiple "plat- virtual void draw() = 0;
// forms" routinely requires lots of };
// preprocessor "case" stmts. The
// Factory pattern suggests defining class MotifBtn : public Widget {
// a creation services interface in a public:
// Factory base class, and implement- void draw() { cout << "MotifBtn"
// ing each "platform" in a separate << endl; }
// Factory derived class. };
#include <iostream.h> class WindowsBtn : public Widget {
public:
class Widget { public: void draw() { cout << "WindowsBtn"
virtual void draw() = 0; << endl; }
}; };
class MotifBtn : public Widget { class Factory { public:
public: virtual Widget* createBtn() = 0;
void draw() { cout << "MotifBtn" };
<< endl; }
}; class MotifFactory : public Factory {
public:
class WindowsBtn : public Widget { Widget* createBtn() {
public: return new MotifBtn; }
void draw() { cout << "WindowsBtn" };
<< endl; }
}; class WindowsFactory : public Factory {
public:
void doThisWindow() { Widget* createBtn() {
// create window, attach btn return new WindowsBtn; }
#ifdef MOTIF };
Widget* w = new MotifBtn;
#else // WINDOWS Factory* factory;
Widget* w = new WindowsBtn;
#endif void doThisWindow() {
w->draw(); } // create window, attach btn
Widget* w = factory->createBtn();
void doThatWindow() { w->draw(); }
// create window, attach btn
#ifdef MOTIF void doThatWindow() {
Widget* w = new MotifBtn; // create window, attach btn
#else // WINDOWS Widget* w = factory->createBtn();
Widget* w = new WindowsBtn; w->draw(); }
#endif
w->draw(); } void main( void )
{
void main( void ) #ifdef MOTIF
{ factory = new MotifFactory;
// create window, attach btn #else // WINDOWS
#ifdef MOTIF factory = new WindowsFactory;
Widget* w = new MotifBtn; #endif
#else // WINDOWS
Widget* w = new WindowsBtn; // create window, attach btn
#endif Widget* w = factory->createBtn();
w->draw(); w->draw();
doThisWindow(); doThisWindow();
doThatWindow(); doThatWindow();
} }
// WindowsBtn // MotifBtn
// WindowsBtn // MotifBtn
// WindowsBtn // MotifBtn
// Purpose. Abstract Factory design pattern demo.
//
// Discussion. "Think of constructors as factories that churn out objects".
// Here we are allocating the constructor responsibility to a factory object,
// and then using inheritance and virtual member functions to provide a
// "virtual constructor" capability. So there are two dimensions of
// decoupling occurring. The client uses the factory object instead of "new"
// to request instances; and, the client "hard-wires" the family, or class, of
// that factory only once, and throughout the remainder of the application
// only relies on the abstract base class.
#include <iostream.h>
class Shape {
public:
Shape() { id_ = total_++; }
virtual void draw() = 0;
protected:
int id_;
static int total_;
};
int Shape::total_ = 0;
class Circle : public Shape { public:
void draw() { cout << "circle " << id_ << ": draw" << endl; } };
class Square : public Shape { public:
void draw() { cout << "square " << id_ << ": draw" << endl; } };
class Ellipse : public Shape { public:
void draw() { cout << "ellipse " << id_ << ": draw" << endl; } };
class Rectangle : public Shape { public:
void draw() { cout << "rectangle " << id_ << ": draw" << endl; } };
class Factory { public:
virtual Shape* createCurvedInstance() = 0;
virtual Shape* createStraightInstance() = 0;
};
class SimpleShapeFactory : public Factory { public:
Shape* createCurvedInstance() { return new Circle; }
Shape* createStraightInstance() { return new Square; }
};
class RobustShapeFactory : public Factory { public:
Shape* createCurvedInstance() { return new Ellipse; }
Shape* createStraightInstance() { return new Rectangle; }
};
void main() {
#ifdef SIMPLE
Factory* factory = new SimpleShapeFactory;
#elif ROBUST
Factory* factory = new RobustShapeFactory;
#endif
Shape* shapes[3];
shapes[0] = factory->createCurvedInstance(); // shapes[0] = new Ellipse;
shapes[1] = factory->createStraightInstance(); // shapes[1] = new Rectangle;
shapes[2] = factory->createCurvedInstance(); // shapes[2] = new Ellipse;
for (int i=0; i < 3; i++)
shapes[i]->draw();
}
// ellipse 0: draw
// rectangle 1: draw
// ellipse 2: draw
// Purpose. Flyweight #include <iostream.h>
//
// Discussion. Trying to use objects const int X = 6;
// at very low levels of granularity const int Y = 10;
// is nice, but the overhead may be
// prohibitive. Flyweight suggests class Gazillion {
// removing the non-shareable state public:
// from the class, and having the cli- Gazillion( int in ) {
// ent supply it when methods are val1_ = in;
// called. This places more respon- cout << "ctor: "<< val1_<<endl; }
// sibility on the client, but, con- ~Gazillion() {
// siderably fewer instances of the cout << val1_ << ' '; }
// Flyweight class are now created. void report( int in ) {
// Sharing of these instances is fa- cout << val1_ << in << ' '; }
// cilitated by introducing a Factory private:
// class that maintains a "cache" of int val1_;
// existing Flyweights. };
//
// In this example, the "X" state is class Factory {
// considered shareable (within each public:
// row anyways), and the "Y" state has static Gazillion* getFly(int in) {
// been externalized (it is supplied if ( ! pool_[in])
// by the client when report() is pool_[in] =
// called). new Gazillion( in );
return pool_[in];
#include <iostream.h> }
static void cleanUp() {
const int X = 6; cout << "dtors: ";
const int Y = 10; for (int i=0; i < X; i++)
if (pool_[i])
class Gazillion { delete pool_[i];
public: cout << endl;
Gazillion() { }
val1_ = num_ / Y; private:
val2_ = num_ % Y; static Gazillion* pool_[X];
num_++; };
}
void report() { Gazillion* Factory::pool_[] = {
cout << val1_ << val2_ << ' '; 0,0,0,0,0,0 };
}
private: void main( void )
int val1_; {
int val2_; for (int i=0; i < X; i++)
static int num_; {
}; for (int j=0; j < Y; j++)
Factory::getFly(i)->report(j);
int Gazillion::num_ = 0; cout << endl;
}
void main( void ) Factory::cleanUp();
{ }
Gazillion matrix[X][Y];
for (int i=0; i < X; i++) // ctor: 0
{ // 00 01 02 03 04 05 06 07 08 09
for (int j=0; j < Y; j++) // ctor: 1
matrix[i][j].report(); // 10 11 12 13 14 15 16 17 18 19
cout << endl; // ctor: 2
} // 20 21 22 23 24 25 26 27 28 29
} // ctor: 3
// 30 31 32 33 34 35 36 37 38 39
// 00 01 02 03 04 05 06 07 08 09 // ctor: 4
// 10 11 12 13 14 15 16 17 18 19 // 40 41 42 43 44 45 46 47 48 49
// 20 21 22 23 24 25 26 27 28 29 // ctor: 5
// 30 31 32 33 34 35 36 37 38 39 // 50 51 52 53 54 55 56 57 58 59
// 40 41 42 43 44 45 46 47 48 49 // dtors: 0 1 2 3 4 5
// 50 51 52 53 54 55 56 57 58 59
// Purpose. Flyweight design pattern demo.
//
// Discussion. Flyweight describes how to share objects, so that their
// use at fine granularities is not cost prohibitive. A key concept is
// the distinction between "intrinsic" and "extrinsic" state. Intrinsic
// state consists of information that is independent of the flyweight's
// context - information that is sharable (i.e. each Icon's name, width,
// and height). It is stored in the flyweight (i.e. the Icon class).
// Extrinsic state cannot be shared, it depends on and varies with the
// flyweight's context (i.e. the x,y position that each Icon instance's
// upper left corner will be drawn at). Extrinsic state is stored or
// computed by the client and is passed to the flyweight when an operation
// is invoked. Clients should not instantiate Flyweights directly, they
// should obtain them exclusively from a FlyweightFactory object to ensure
// they are shared properly.
#include <iostream.h>
#include <string.h>
class Icon {
public:
Icon( char* fileName ) {
strcpy( _name, fileName );
if ( ! strcmp(fileName, "go")) { _width = 20; _height = 20; }
if ( ! strcmp(fileName, "stop")) { _width = 40; _height = 40; }
if ( ! strcmp(fileName, "select")) { _width = 60; _height = 60; }
if ( ! strcmp(fileName, "undo")) { _width = 30; _height = 30; } }
const char* getName() { return _name; }
draw( int x, int y ) {
cout << " drawing " << _name << ": upper left (" << x << "," << y
<< ") - lower right (" << x + _width << "," << y + _height << ")"
<< endl; }
private:
char _name[20];
int _width;
int _height;
};
class FlyweightFactory {
public:
static Icon* getIcon( char* name ) {
for (int i=0; i < _numIcons; i++)
if ( ! strcmp( name, _icons[i]->getName() ))
return _icons[i];
_icons[_numIcons] = new Icon( name );
return _icons[_numIcons++]; }
static void reportTheIcons() {
cout << "Active Flyweights: ";
for (int i=0; i < _numIcons; i++)
cout << _icons[i]->getName() << " ";
cout << endl; }
private:
enum { MAX_ICONS = 5 };
static int _numIcons;
static Icon* _icons[MAX_ICONS];
};
int FlyweightFactory::_numIcons = 0;
Icon* FlyweightFactory::_icons[];
class DialogBox {
public:
DialogBox( int x, int y, int incr ) : _iconsOriginX(x), _iconsOriginY(y),
_iconsXIncrement(incr) { }
virtual void draw() = 0;
protected:
Icon* _icons[3];
int _iconsOriginX;
int _iconsOriginY;
int _iconsXIncrement;
};
class FileSelection : public DialogBox {
public:
FileSelection( Icon* first, Icon* second, Icon* third ) :
DialogBox(100,100,100) {
_icons[0] = first;
_icons[1] = second;
_icons[2] = third; }
void draw() {
cout << "drawing FileSelection:" << endl;
for (int i=0; i < 3; i++)
_icons[i]->draw( _iconsOriginX + (i * _iconsXIncrement),
_iconsOriginY ); }
};
class CommitTransaction : public DialogBox {
public:
CommitTransaction( Icon* first, Icon* second, Icon* third ) :
DialogBox(150,150,150) {
_icons[0] = first;
_icons[1] = second;
_icons[2] = third; }
void draw() {
cout << "drawing CommitTransaction:" << endl;
for (int i=0; i < 3; i++)
_icons[i]->draw( _iconsOriginX + (i * _iconsXIncrement),
_iconsOriginY ); }
};
void main() {
DialogBox* dialogs[2];
dialogs[0] = new FileSelection(
FlyweightFactory::getIcon("go"),
FlyweightFactory::getIcon("stop"),
FlyweightFactory::getIcon("select") );
dialogs[1] = new CommitTransaction(
FlyweightFactory::getIcon("select"),
FlyweightFactory::getIcon("stop"),
FlyweightFactory::getIcon("undo") );
for (int i=0; i < 2; i++)
dialogs[i]->draw();
FlyweightFactory::reportTheIcons();
}
// drawing FileSelection:
// drawing go: upper left (100,100) - lower right (120,120)
// drawing stop: upper left (200,100) - lower right (240,140)
// drawing select: upper left (300,100) - lower right (360,160)
// drawing CommitTransaction:
// drawing select: upper left (150,150) - lower right (210,210)
// drawing stop: upper left (300,150) - lower right (340,190)
// drawing undo: upper left (450,150) - lower right (480,180)
// Active Flyweights: go stop select undo
// Purpose. Direct coupling, lots of start-up and shut-down overhead
#include <iostream>
#include <string>
using namespace std;
class Image {
int id;
static int next;
public:
Image() { id = next++; cout << " $$ ctor: "<< id << '\n'; }
~Image() { cout << " dtor: " << id << '\n'; }
void draw() { cout << " drawing image " << id << '\n'; }
};
int Image::next = 1;
void main( void ) {
Image images[5];
int i;
cout << "Exit[0], Image[1-5]: ";
cin >> i;
while (i) {
images[i-1].draw();
cout << "Exit[0], Image[1-5]: ";
cin >> i;
} }
// $$ ctor: 1
// $$ ctor: 2
// $$ ctor: 3
// $$ ctor: 4
// $$ ctor: 5
// Exit[0], Image[1-5]: 2
// drawing image 2
// Exit[0], Image[1-5]: 4
// drawing image 4
// Exit[0], Image[1-5]: 2
// drawing image 2
// Exit[0], Image[1-5]: 0
// dtor: 5
// dtor: 4
// dtor: 3
// dtor: 2
// dtor: 1
// Purpose. Proxy design pattern
// 1. Design an "extra level of indirection" wrapper class
// 2. The wrapper class holds a pointer to the real class
// 3. The pointer is initialized to null
// 4. When a request comes in, the real object is created "on first use"
// (aka lazy intialization)
// 5. The request is always delegated
class RealImage {
int id;
public:
RealImage( int i ) { id = i; cout << " $$ ctor: "<< id << '\n'; }
~RealImage() { cout << " dtor: " << id << '\n'; }
void draw() { cout << " drawing image " << id << '\n'; }
};
// 1. Design an "extra level of indirection" wrapper class
class Image {
// 2. The wrapper class holds a pointer to the real class
RealImage* theRealThing;
int id;
static int next;
public:
Image() { id = next++; theRealThing = 0; } // 3. Initialized to null
~Image() { delete theRealThing; }
void draw() {
// 4. When a request comes in, the real object is created "on first use"
if ( ! theRealThing) theRealThing = new RealImage( id );
// 5. The request is always delegated
theRealThing->draw();
} };
int Image::next = 1;
void main( void ) {
Image images[5];
int i;
cout << "Exit[0], Image[1-5]: ";
cin >> i;
while (i) {
images[i-1].draw();
cout << "Exit[0], Image[1-5]: ";
cin >> i;
} }
// Exit[0], Image[1-5]: 2
// $$ ctor: 2
// drawing image 2
// Exit[0], Image[1-5]: 4
// $$ ctor: 4
// drawing image 4
// Exit[0], Image[1-5]: 2
// drawing image 2
// Exit[0], Image[1-5]: 4
// drawing image 4
// Exit[0], Image[1-5]: 0
// dtor: 4
// dtor: 2
// Purpose. "->" and "." operators give different results
class Subject { public: virtual void execute() = 0; };
class RealSubject : public Subject {
string str;
public:
RealSubject( string s ) { str = s; }
/*virtual*/ void execute() { cout << str << '\n'; }
};
class ProxySubject : public Subject {
string first, second, third;
RealSubject* ptr;
public:
ProxySubject( string s ) {
int num = s.find_first_of( ' ' );
first = s.substr( 0, num ); s = s.substr( num+1 );
num = s.find_first_of( ' ' );
second = s.substr( 0, num ); s = s.substr( num+1 );
num = s.find_first_of( ' ' );
third = s.substr( 0, num ); s = s.substr( num+1 );
ptr = new RealSubject( s );
}
~ProxySubject() { delete ptr; }
RealSubject* operator->() {
cout << first << ' ' << second << ' ';
return ptr;
}
/*virtual*/ void execute() {
cout << first << ' ' << third << ' ';
ptr->execute();
}
};
void main( void ) {
ProxySubject obj( string( "the quick brown fox jumped over the dog" ) );
obj->execute();
obj.execute();
}
// the quick fox jumped over the dog
// the brown fox jumped over the dog
// Purpose. "A protection proxy controls access to the original object."
class Person {
string nameString;
static string list[];
static int next;
public:
Person() { nameString = list[next++]; }
string name() { return nameString; }
};
string Person::list[] = { "Tom", "Dick", "Harry", "Bubba" };
int Person::next = 0;
class PettyCashProtected {
int balance;
public:
PettyCashProtected() { balance = 500; }
bool withdraw( int amount ) {
if (amount > balance) return false;
balance -= amount;
return true;
}
int getBalance() { return balance; }
};
class PettyCash {
PettyCashProtected realThing;
public:
bool withdraw( Person& p, int amount ) {
if (p.name() == "Tom" || p.name() == "Harry" || p.name() == "Bubba")
return realThing.withdraw( amount );
else return false;
}
int getBalance() { return realThing.getBalance(); }
};
void main( void ) {
PettyCash pc;
Person workers[4];
for (int i=0, amount=100; i < 4; i++, amount += 100)
if ( ! pc.withdraw( workers[i], amount ))
cout << "No money for " << workers[i].name() << '\n';
else
cout << amount << " dollars for " << workers[i].name() << '\n';
cout << "Remaining balance is " << pc.getBalance() << '\n';
}
// 100 dollars for Tom
// No money for Dick
// 300 dollars for Harry
// No money for Bubba
// Remaining balance is 100
// Purpose. Simulate a Persistent Object Pointer
template <typename TBD>
class POP { // Persistent Object Pointer
string oid;
TBD* ptr;
public:
POP( string id ) { oid = id; ptr = 0; }
~POP() { delete ptr; }
TBD* operator->() {
if ( ! ptr)
// simulate the persistence mechanism
ptr = new TBD( oid );
return ptr;
} };
class Person {
string name;
int age;
public:
Person( string n ) { name = n; }
string getName() { return name; }
int getAge() { return 32; }
};
void main( void ) {
POP<Person> ph( "Tom" );
cout << "policy holder is " << ph->getName() << ", age is " << ph->getAge() << '\n';
}
// policy holder is Tom, age is 32
// Purpose. Chain of Responsibility. #include <iostream.h>
//
// Discussion. Instead of the client class H {
// having to know about the number of public:
// "handlers", and manually map re- H( H* next = 0 ) {
// quests to available handlers; de- id_ = count_++;
// sign the handlers into an "intel- busy_ = 0;
// ligent" chain. Clients "launch next_ = next;
// and leave" requests with the head }
// of the chain. ~H() {
cout << id_<<" dtor" << endl;
#include <iostream.h> // don't get into a loop
if (next_->next_) {
class H { H* t = next_;
public: next_ = 0;
H() { delete t;
id_ = count_++; } }
busy_ = 0; void setNext( H* next ) {
} next_ = next;
~H() { }
cout << id_ << " dtor" << endl; void handle() {
} if (busy_ = ! busy_)
int handle() { cout << id_ << " handles"
if (busy_ = ! busy_) { << endl;
cout << id_ << " handles" else {
<< endl; cout << id_ << " is busy"
return 1; << endl;
} else { next_->handle();
cout << id_ << " is busy" } }
<< endl; private:
return 0; int id_, busy_;
} } H* next_;
private: static int count_;
int id_, busy_; };
static int count_; int H::count_ = 1;
};
int H::count_ = 1; H* setUpList() {
H* first = new H;
void main( void ) { H* last = new H(first);
const int TOTAL = 2; first->setNext( last );
H* list[TOTAL] = { new H, new H }; return first;
}
for (int i=0; i < 6; i++)
for (int j=0; 1 ; void main( void ) {
j = (j + 1) % TOTAL) H* head = setUpList();
if (list[j]->handle())
break; for (int i=0; i < 6; i++)
head->handle();
for (int k=0; k < TOTAL; k++)
delete list[k]; delete head;
} }
// 1 handles // 1 handles
// 1 is busy // 1 is busy
// 2 handles // 2 handles
// 1 handles // 1 handles
// 1 is busy // 1 is busy
// 2 is busy // 2 is busy
// 1 handles // 1 handles
// 1 is busy // 1 is busy
// 2 handles // 2 handles
// 1 handles // 1 handles
// 1 dtor // 1 dtor
// 2 dtor // 2 dtor
// Purpose. Chain of Responsibility design pattern
// 1. Put a "next" pointer in the base class
// 2. The "chain" method in the base class always delegates to the next object
// 3. If the derived classes cannot handle, they delegate to the base class
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
class Base {
Base* next; // 1. "next" pointer in the base class
public:
Base() { next = 0; }
void setNext( Base* n ) { next = n; }
void add( Base* n ) { if (next) next->add( n ); else next = n; }
// 2. The "chain" method in the base class always delegates to the next obj
virtual void handle( int i ) { next->handle( i ); }
};
class Handler1 : public Base { public:
/*virtual*/ void handle( int i ) {
if (rand() % 3) { // 3. Don't handle requests 3 times out of 4
cout << "H1 passsed " << i << " ";
Base::handle( i ); // 3. Delegate to the base class
} else
cout << "H1 handled " << i << " ";
} };
class Handler2 : public Base { public:
/*virtual*/ void handle( int i ) {
if (rand() % 3) { cout << "H2 passsed " << i << " "; Base::handle( i ); }
else cout << "H2 handled " << i << " ";
} };
class Handler3 : public Base { public:
/*virtual*/ void handle( int i ) {
if (rand() % 3) { cout << "H3 passsed " << i << " "; Base::handle( i ); }
else cout << "H3 handled " << i << " ";
} };
void main( void ) {
srand( time( 0 ) );
Handler1 root; Handler2 two; Handler3 thr;
root.add( &two ); root.add( &thr );
thr.setNext( &root );
for (int i=1; i < 10; i++) {
root.handle( i ); cout << '\n';
} }
// H1 passsed 1 H2 passsed 1 H3 passsed 1 H1 passsed 1 H2 handled 1
// H1 handled 2
// H1 handled 3
// H1 passsed 4 H2 passsed 4 H3 handled 4
// H1 passsed 5 H2 handled 5
// H1 passsed 6 H2 passsed 6 H3 passsed 6 H1 handled 6
// H1 passsed 7 H2 passsed 7 H3 passsed 7 H1 passsed 7 H2 handled 7
// H1 handled 8
// H1 passsed 9 H2 passsed 9 H3 handled 9
// Purpose. Chain of Responsibility and Composite
// 1. Put a "next" pointer in the base class
// 2. The "chain" method in the base class always delegates to the next object
// 3. If the derived classes cannot handle, they delegate to the base class
#include <iostream>
#include <vector>
#include <ctime>
using namespace std;
class Component {
int value;
Component* next; // 1. "next" pointer in the base class
public:
Component( int v, Component* n ) { value = v; next = n; }
void setNext( Component* n ) { next = n; }
virtual void traverse() { cout << value << ' '; }
// 2. The "chain" method in the base class always delegates to the next obj
virtual void volunteer() { next->volunteer(); }
};
class Primitive : public Component { public:
Primitive( int val, Component* n = 0 ) : Component( val, n ) { }
/*virtual*/ void volunteer() {
Component::traverse();
// 3. Primitive objects don't handle volunteer requests 5 times out of 6
if (rand() * 100 % 6 != 0)
// 3. Delegate to the base class
Component::volunteer();
} };
class Composite : public Component {
vector<Component*> children;
public:
Composite( int val, Component* n = 0 ) : Component( val, n ) { }
void add( Component* c ) { children.push_back( c ); }
/*virtual*/ void traverse() {
Component::traverse();
for (int i=0; i < children.size(); i++)
children[i]->traverse();
}
// 3. Composite objects never handle volunteer requests
/*virtual*/ void volunteer() { Component::volunteer(); }
};
void main( void ) {
srand( time( 0 ) ); // 1
Primitive seven( 7 ); // |
Primitive six( 6, &seven ); // +-- 2
Composite three( 3, &six ); // | |
three.add( &six ); three.add( &seven ); // | +-- 4 5
Primitive five( 5, &three ); // |
Primitive four( 4, &five ); // +-- 3
Composite two( 2, &four ); // | |
two.add( &four ); two.add( &five ); // | +-- 6 7
Composite one( 1, &two ); // |
Primitive nine( 9, &one ); // +-- 8 9
Primitive eight( 8, &nine );
one.add( &two ); one.add( &three ); one.add( &eight ); one.add( &nine );
seven.setNext( &eight );
cout << "traverse: "; one.traverse(); cout << '\n';
for (int i=0; i < 8; i++) {
one.volunteer(); cout << '\n';
} }
// traverse: 1 2 4 5 3 6 7 8 9
// 4
// 4 5 6 7
// 4 5 6 7 8 9 4 5 6 7 8 9 4
// 4
// 4 5 6
// 4 5
// 4 5
// 4 5 6 7 8 9 4 5 6 7 8 9 4 5 6
// Purpose. Chain of Responsibility - links bid on job, chain assigns job
//
// 1. Base class maintains a "next" pointer
// 2. Each "link" does its part to handle (and/or pass on) the request
// 3. Client "launches and leaves" each request with the chain
// 4. The current bid and bidder are maintained in chain static members
// 5. The last link in the chain assigns the job to the low bidder
#include <iostream>
#include <ctime>
using namespace std;
class Link {
int id;
Link* next; // 1. "next" pointer
static int theBid; // 4. Current bid and bidder
static Link* bidder;
public:
Link( int num ) { id = num; next = 0; }
void addLast( Link* l ) {
if (next) next->addLast( l ); // 2. Handle and/or pass on
else next = l;
}
void bid() {
int num = rand() % 9;
cout << id << '-' << num << " ";
if (num < theBid) {
theBid = num; // 4. Current bid and bidder
bidder = this;
}
if (next) next->bid(); // 2. Handle and/or pass on
else bidder->execute(); // 5. The last 1 assigns the job
}
void execute() {
cout << id << " is executing\n";
theBid = 999;
} };
int Link::theBid = 999; // 4. Current bid and bidder
Link* Link::bidder = 0;
void main( void ) {
Link chain( 1 );
for (int i=2; i < 7; i++)
chain.addLast( new Link( i ) );
srand( time( 0 ) );
for (i=0; i < 10; i++)
chain.bid(); // 3. Client "launches & leaves"
}
// 1-1 2-6 3-0 4-3 5-1 6-0 3 is executing
// 1-1 2-1 3-1 4-0 5-7 6-1 4 is executing
// 1-0 2-1 3-0 4-6 5-1 6-2 1 is executing
// 1-6 2-3 3-8 4-0 5-1 6-4 4 is executing
// 1-8 2-0 3-5 4-8 5-4 6-2 2 is executing
// 1-1 2-0 3-8 4-8 5-7 6-0 2 is executing
// 1-1 2-1 3-3 4-1 5-6 6-2 1 is executing
// 1-2 2-1 3-0 4-3 5-6 6-8 3 is executing
// 1-7 2-5 3-4 4-2 5-1 6-2 5 is executing
// 1-3 2-6 3-7 4-7 5-6 6-0 6 is executing
// Purpose. Command class Deadbeat {
// public:
// Discussion. On the left, an IOU Deadbeat( int v ) { cash_ = v; }
// has been encapsulated as a struct, int payUp( int v ) {
// and TheBoss class is tightly coup- cash_ -= v; return v; }
// led to that struct. On the right, int rptCash() { return cash_; }
// TheBoss is only coupled to the ab- private:
// stract class Command. Lots of pos- int cash_;
// sible derived classes could be sub- };
// stituted: IOUs that call payUp() on
// Deadbeats, Checks that call cash() class Command { public:
// on Banks, Stocks that call redeem() virtual int execute() = 0;
// on Companies. Each "command" is a };
// "token" that gets transfered from
// one holder to another, until some- class IOU : public Command {
// one chooses to "execute" it. public:
typedef int (Deadbeat::*Meth)(int);
class Deadbeat { public: IOU( Deadbeat* r, Meth a, int m ) {
Deadbeat( int v ) { cash_ = v; } obj_ = r;
int payUp( int v ) { mth_ = a;
cash_ -= v; return v; } amt_ = m; }
int rptCash() { return cash_; } int execute() {
private: return (obj_->*mth_)( amt_ ); }
int cash_; private:
}; Deadbeat* obj_;
Meth mth_;
struct IOU { int amt_;
Deadbeat* objPtr; };
int (Deadbeat::*funPtr)( int );
int amt; class Enforcer {
}; public:
Enforcer( Command& c ) : cmd_(c) {}
class Enforcer { public: Command& collect() { return cmd_; }
Enforcer( IOU& m ) : mkr_(m) { } private:
IOU& collect() { return mkr_; } Command& cmd_;
private: };
IOU& mkr_;
}; class TheBoss {
public:
class TheBoss { TheBoss() { cash_ = 1000; }
public: collect( Command& cmd ) {
TheBoss() { cash_ = 1000; } cash_ += cmd.execute(); }
collect( IOU& i ) { int rptCash() { return cash_; }
cash_ += private:
((i.objPtr)->*i.funPtr)(i.amt) int cash_;
} };
int rptCash() { return cash_; }
private: void main( void )
int cash_; {
}; Deadbeat joe(90), tom(90);
IOU one(&joe, &Deadbeat::payUp, 60);
void main( void ) IOU two(&tom, &Deadbeat::payUp, 70);
{ Enforcer quido(one), lucca(two);
Deadbeat joe(90), tom(90); TheBoss don;
IOU one ={&joe, &Deadbeat::payUp,60}
IOU two ={&tom, &Deadbeat::payUp,70} don.collect( quido.collect() );
Enforcer quido(one), lucca(two); don.collect( lucca.collect() );
TheBoss don; cout << "joe has $" << joe.rptCash()
cout << "tom has $" << tom.rptCash()
don.collect( quido.collect() ); cout << "don has $" << don.rptCash()
don.collect( lucca.collect() ); }
cout << "joe has $" << joe.rptCash()
cout << "tom has $" << tom.rptCash() // joe has $30
cout << "don has $" << don.rptCash() // tom has $20
} // don has $1130
// Purpose. Command design pattern
// 1. Create a class that encapsulates some number of the following:
// a "receiver" object
// the method to invoke
// the arguments to pass
// 2. Instantiate an object for each "callback"
// 3. Pass each object to its future "sender"
// 4. When the sender is ready to callback to the receiver, it calls execute()
#include <iostream> #include <string> using namespace std;
class Person;
class Command { // 1. Create a class that encapsulates an object
Person* object; // and a member function
void (Person::*method)(); // a pointer to a member function (the attri-
public: // bute's name is "method")
Command( Person* obj = 0, void (Person::*meth)() = 0 ) {
object = obj; // the argument's name is "meth"
method = meth;
}
void execute() {
(object->*method)(); // invoke the method on the object
} };
class Person {
string name;
Command cmd; // cmd is a "black box", it is a method invoca-
public: // tion promoted to "full object status"
Person( string n, Command c ) : cmd( c ) {
name = n;
}
void talk() { // "this" is the sender, cmd has the receiver
cout << name << " is talking" << endl;
cmd.execute(); // ask the "black box" to callback the receiver
}
void passOn() {
cout << name << " is passing on" << endl;
cmd.execute(); // 4. When the sender is ready to callback to
} // the receiver, it calls execute()
void gossip() {
cout << name << " is gossiping" << endl;
cmd.execute();
}
void listen() {
cout << name << " is listening" << endl;
} };
void main( void ) {
// Fred will "execute" Barney which will result in a call to passOn()
// Barney will "execute" Betty which will result in a call to gossip()
// Betty will "execute" Wilma which will result in a call to listen()
Person wilma( "Wilma", Command() );
// 2. Instantiate an object for each "callback"
// 3. Pass each object to its future "sender"
Person betty( "Betty", Command( &wilma, &Person::listen ) );
Person barney( "Barney", Command( &betty, &Person::gossip ) );
Person fred( "Fred", Command( &barney, &Person::passOn ) );
fred.talk();
}
// Fred is talking
// Barney is passing on
// Betty is gossiping
// Wilma is listening
// Purpose. Simple and "macro" commands
//
// Discussion. Encapsulate a request as an object. SimpleCommand
// maintains a binding between a receiver object and an action stored as a
// pointer to a member function. MacroCommand maintains a sequence of
// Commands. No explicit receiver is required because the subcommands
// already define their receiver. MacroCommand may contain MacroCommands.
#include <iostream>
#include <vector>
using namespace std;
class Number { public:
void dubble( int& value ) { value *= 2; }
};
class Command { public: virtual void execute( int& ) = 0; };
class SimpleCommand : public Command {
typedef void (Number::* Action)(int&);
Number* receiver;
Action action;
public:
SimpleCommand( Number* rec, Action act ) {
receiver = rec;
action = act;
}
/*virtual*/ void execute( int& num ) { (receiver->*action)( num ); }
};
class MacroCommand : public Command {
vector<Command*> list;
public:
void add( Command* cmd ) { list.push_back( cmd ); }
/*virtual*/ void execute( int& num ) {
for (int i=0; i < list.size(); i++)
list[i]->execute( num );
} };
void main( void ) {
Number object;
Command* commands[3];
commands[0] = &SimpleCommand( &object, &Number::dubble );
MacroCommand two;
two.add( commands[0] ); two.add( commands[0] );
commands[1] = &two;
MacroCommand four;
four.add( &two ); four.add( &two );
commands[2] = &four;
int num, index;
while (true) {
cout << "Enter number selection (0=2x 1=4x 2=16x): ";
cin >> num >> index;
commands[index]->execute( num );
cout << " " << num << '\n';
} }
// Enter number selection (0=2x 1=4x 2=16x): 3 0
// 6
// Enter number selection (0=2x 1=4x 2=16x): 3 1
// 12
// Enter number selection (0=2x 1=4x 2=16x): 3 2
// 48
// Enter number selection (0=2x 1=4x 2=16x): 4 0
// 8
// Enter number selection (0=2x 1=4x 2=16x): 4 1
// 16
// Enter number selection (0=2x 1=4x 2=16x): 4 2
// 64
// Purpose. Command design pattern and inheritance
//
// Discussion. The Command pattern promotes a deferred method invocation to
// full object status. Each Command object is a "black box" - it is opaque to
// its holder/user. Here, a portfolio's heterogeneous collection of financial
// instruments is being treated homogeneously, because, they all inherit from
// a common base class, and, they all have a "convert to currency" method with
// a common signature.
#include <iostream>
using namespace std;
class Instrument { public: virtual ~Instrument() { } };
class IOU : public Instrument {
int amount;
public:
IOU( int in ) { amount = in; }
int payUp() { return amount; }
};
class Check : public Instrument {
int amount;
public:
Check( int in ) { amount = in; }
int cash() { return amount; }
};
class Stock : public Instrument {
int amount;
public:
Stock( int in ) { amount = in; }
int redeem() { return amount; }
};
class Command {
public:
typedef int (Instrument::*Action)();
Command( Instrument* o, Action m ) {
object = o;
method = m;
}
int execute() { return (object->*method)(); }
private:
Instrument* object;
Action method;
};
void main( void ) {
Command* portfolio[] = { // old C cast, or new RTTI is required
&Command( &IOU(100), (int(Instrument::*)())&IOU::payUp ),
&Command( &Check(200), static_cast<int(Instrument::*)()>(&Check::cash) ),
&Command( &Stock(300), static_cast<int(Instrument::*)()>(&Stock::redeem) ) };
for (int netWorth=0, i=0; i < 3; i++)
netWorth += portfolio[i]->execute();
cout << "net worth is now " << netWorth << '\n';
}
// net worth is now 600
// Purpose. Command design pattern and class template
#include <iostream>
#include <string>
using namespace std;
class A {
int divisor;
public:
A( int div ) { divisor = div; }
int divide( int in ) { return in / divisor; }
int modulus( int in ) { return in % divisor; }
};
class B {
string str;
public:
B( string s ) { str = s; }
string prepend( string in ) { return in + str; }
string postpend( string in ) { return str + in; }
};
template <typename CLS, typename ARG>
class Command {
public:
typedef ARG (CLS::*Action)( ARG );
Command( CLS* o, Action m, ARG a ) {
object = o;
method = m;
argument = a;
}
ARG execute() { return (object->*method)( argument ); }
private:
CLS* object;
Action method;
ARG argument;
};
void main( void ) {
Command<A,int>* list1[4] = {
&Command<A,int>( &A(3), &A::divide, 16 ),
&Command<A,int>( &A(3), &A::modulus, 16 ),
&Command<A,int>( &A(4), &A::divide, 16 ),
&Command<A,int>( &A(4), &A::modulus, 16 ) };
for (int i=0; i < 4; i++)
cout << "numbers are " << list1[i]->execute() << '\n';
B obj("abc");
Command<B,string>* list2[4] = {
new Command<B,string>( &obj, &B::prepend, "123" ),
new Command<B,string>( &obj, &B::prepend, "xyz" ),
new Command<B,string>( &obj, &B::postpend, "123" ),
new Command<B,string>( &obj, &B::postpend, "xyz" ) };
for (i=0; i < 4; i++)
cout << "strings are " << list2[i]->execute() << '\n';
}
// numbers are 5
// numbers are 1
// numbers are 4
// numbers are 0
// strings are 123abc
// strings are xyzabc
// strings are abc123
// strings are abcxyz
// Purpose. Command/Adapter design pattern (External Polymorphism demo)
// 1. Specify the new desired interface
// 2. Design a "wrapper" class that can "impedance match" the old to the new
// 3. The client uses (is coupled to) the new interface
// 4. The wrapper/adapter "maps" to the legacy implementation
#include <iostream.h>
class ExecuteInterface { public: // 1. Specify the new i/f
virtual ~ExecuteInterface() { }
virtual void execute() = 0;
};
template <class TYPE> // 2. Design a "wrapper" or
class ExecuteAdapter : public ExecuteInterface { // "adapter" class
public:
ExecuteAdapter( TYPE* o, void (TYPE::*m)() ) { object = o; method =m; }
~ExecuteAdapter() { delete object; }
// 4. The adapter/wrapper "maps" the new to the legacy implementation
void execute() /* the new */ { (object->*method)(); }
private:
TYPE* object; // ptr-to-object attribute
void (TYPE::*method)(); /* the old */ // ptr-to-member-function
}; // attribute
// The old: three totally incompatible classes // no common base class,
class Fea { public: // no hope of polymorphism
~Fea() { cout << "Fea::dtor" << endl; }
void doThis() { cout << "Fea::doThis()" << endl; }
};
class Feye { public:
~Feye() { cout << "Feye::dtor" << endl; }
void doThat() { cout << "Feye::doThat()" << endl; }
};
class Pheau { public:
~Pheau() { cout << "Pheau::dtor" << endl; }
void doTheOther() { cout << "Pheau::doTheOther()" << endl; }
};
/* the new is returned */ ExecuteInterface** initialize() {
ExecuteInterface** array = new ExecuteInterface*[3]; /* the old is below */
array[0] = new ExecuteAdapter<Fea>( new Fea(), &Fea::doThis );
array[1] = new ExecuteAdapter<Feye>( new Feye(), &Feye::doThat );
array[2] = new ExecuteAdapter<Pheau>( new Pheau(), &Pheau::doTheOther );
return array;
}
void main( void ) {
ExecuteInterface** objects = initialize();
for (int i=0; i < 3; i++) objects[i]->execute(); // 3. Client uses the new
// (polymporphism)
for (i=0; i < 3; i++) delete objects[i];
delete objects;
}
// Fea::doThis()
// Feye::doThat()
// Pheau::doTheOther()
// Fea::dtor
// Feye::dtor
// Pheau::dtor
// Purpose. Command design pattern demo
//
// Discussion. Encapsulate a request as an object. SimpleCommand
// maintains a binding between a receiver object and an action stored as a
// pointer to a member function. MacroCommand maintains a sequence of
// Commands. No explicit receiver is required because the subcommands
// already define their receiver. MacroCommand may contain MacroCommands.
#include <iostream.h>
class Number {
public:
Number( int value ) { _value = _copy = value; }
int getValue() { return _value; }
void increment() { _copy = _value++; }
void decrement() { _copy = _value--; }
void restore() { _value = _copy; }
void dubble() { _copy = _value; _value = 2 * _value; }
void half() { _copy = _value; _value = _value / 2; }
void square() { _copy = _value; _value = _value * _value; }
private:
int _value;
int _copy;
};
class Command {
public:
virtual void execute() = 0;
virtual void add( Command* ) { }
protected:
Command() { }
};
class SimpleCommand : public Command {
public:
typedef void (Number::* Action)();
SimpleCommand( Number* receiver, Action action ) {
_receiver = receiver;
_action = action; }
virtual void execute() { (_receiver->*_action)(); }
protected:
Number* _receiver;
Action _action;
};
class MacroCommand : public Command {
public:
MacroCommand() { _numCommands = 0; }
void add( Command* cmd ) { _list[_numCommands++] = cmd; }
virtual void execute();
private:
Command* _list[10];
int _numCommands;
};
void MacroCommand::execute() {
for (int i=0; i < _numCommands; i++)
_list[i]->execute();
}
void main() {
int i;
cout << "Integer: ";
cin >> i;
Number* object = new Number(i);
Command* commands[9];
commands[1] = new SimpleCommand( object, &Number::increment );
commands[2] = new SimpleCommand( object, &Number::decrement );
commands[3] = new SimpleCommand( object, &Number::dubble );
commands[4] = new SimpleCommand( object, &Number::half );
commands[5] = new SimpleCommand( object, &Number::square );
commands[6] = new SimpleCommand( object, &Number::restore );
commands[7] = new MacroCommand;
commands[7]->add( commands[1] );
commands[7]->add( commands[3] );
commands[7]->add( commands[5] );
commands[8] = new MacroCommand;
commands[8]->add( commands[7] );
commands[8]->add( commands[7] );
cout << "Exit[0], ++[1], --[2], x2[3], Half[4], Square[5], "
<< "Undo[6], do3[7] do6[8]: ";
cin >> i;
while (i)
{
commands[i]->execute();
cout << " " << object->getValue() << endl;
cout << "Exit[0], ++[1], --[2], x2[3], Half[4], Square[5], "
<< "Undo[6], do3[7] do6[8]: ";
cin >> i;
}
}
// Integer: 4
// Exit[0], ++[1], --[2], x2[3], Half[4], Square[5], Undo[6], do3[7] do6[8]: 1
// 5
// Exit[0], ++[1], --[2], x2[3], Half[4], Square[5], Undo[6], do3[7] do6[8]: 3
// 10
// Exit[0], ++[1], --[2], x2[3], Half[4], Square[5], Undo[6], do3[7] do6[8]: 2
// 9
// Exit[0], ++[1], --[2], x2[3], Half[4], Square[5], Undo[6], do3[7] do6[8]: 4
// 4
// Exit[0], ++[1], --[2], x2[3], Half[4], Square[5], Undo[6], do3[7] do6[8]: 5
// 16
// Exit[0], ++[1], --[2], x2[3], Half[4], Square[5], Undo[6], do3[7] do6[8]: 6
// 4
// Exit[0], ++[1], --[2], x2[3], Half[4], Square[5], Undo[6], do3[7] do6[8]: 6
// 4
// Exit[0], ++[1], --[2], x2[3], Half[4], Square[5], Undo[6], do3[7] do6[8]: 7
// 100
// Exit[0], ++[1], --[2], x2[3], Half[4], Square[5], Undo[6], do3[7] do6[8]: 6
// 10
// Exit[0], ++[1], --[2], x2[3], Half[4], Square[5], Undo[6], do3[7] do6[8]: 8
// 940900
// Purpose. Interpreter private:
// C c; D d;
// Define a grammar for a language, };
// and map each rule to a class.
class Acti { public:
#include <iostream.h> int eval( char* i, char* o ) {
#include <string.h> if (e.eval(i,o)) return 1;
if (f.eval(i,o)) return 1;
int sub(char* i, char* o, char* c) { return 0; }
strcat(o, c); strcpy(i, &(i[1])); private:
return 1; } E e; F f;
};
class A { public: class Pass { public:
int eval( char* i, char* o ) { int eval( char* i, char* o ) {
if (i[0] == 'a') if (g.eval(i,o)) return 1;
return sub(i,o,"1"); if (h.eval(i,o)) return 1;
return 0; } }; return 0; }
class B { public: private:
int eval( char* i, char* o ) { G g; H h;
if (i[0] == 'b') };
return sub(i,o,"2");
return 0; } }; class NP { public:
class C { public: int eval( char* i, char* o ) {
int eval( char* i, char* o ) { if (arti.eval(i,o))
if (i[0] == 'c') if (noun.eval(i,o)) return 1;
return sub(i,o,"3"); return 0; }
return 0; } }; private:
class D { public: Arti arti; Noun noun;
int eval( char* i, char* o ) { };
if (i[0] == 'd') class Verb { public:
return sub(i,o,"4"); int eval( char* i, char* o ) {
return 0; } }; if (acti.eval(i,o)) return 1;
class E { public: if (pass.eval(i,o)) return 1;
int eval( char* i, char* o ) { return 0; }
if (i[0] == 'e') private:
return sub(i,o,"5"); Acti acti; Pass pass;
return 0; } }; };
class F { public:
int eval( char* i, char* o ) { class Sent { public:
if (i[0] == 'f') int eval( char* i, char* o ) {
return sub(i,o,"6"); if (np.eval(i,o))
return 0; } }; if (verb.eval(i,o)) return 1;
class G { public: return 0; }
int eval( char* i, char* o ) { private:
if (i[0] == 'g') NP np; Verb verb;
return sub(i,o,"7"); };
return 0; } };
class H { public: void main( void )
int eval( char* i, char* o ) { {
if (i[0] == 'h') Sent S; char* t[] = {"ace","bdh",
return sub(i,o,"8"); "abc","ceg","bcfgh"};
return 0; } }; char i[10], o[10];
for (int j=0; j < 5; j++) {
class Arti { public: strcpy(i,t[j]); strcpy(o,"");
int eval( char* i, char* o ) { cout << i << " is ";
if (a.eval(i,o)) return 1; if ( ! S.eval(i,o) || i[0])
if (b.eval(i,o)) return 1; cout << "bad" << endl;
return 0; } else
private: cout << o << endl; }
A a; B b; }
};
class Noun { public: // ace is 135
int eval( char* i, char* o ) { // bdh is 248
if (c.eval(i,o)) return 1; // abc is bad
if (d.eval(i,o)) return 1; // ceg is bad
return 0; } // bcfgh is bad
// Purpose. Interpreter design pattern demo (with Template Method)
//
// Discussion. Uses a class hierarchy to represent the grammar given
// below. When a roman numeral is provided, the class hierarchy validates
// and interprets the string. RNInterpreter "has" 4 sub-interpreters.
// Each sub-interpreter receives the "context" (remaining unparsed string
// and cumulative parsed value) and contributes its share to the processing.
// Sub-interpreters simply define the Template Methods declared in the base
// class RNInterpreter.
// romanNumeral ::= {thousands} {hundreds} {tens} {ones}
// thousands, hundreds, tens, ones ::= nine | four | {five} {one} {one} {one}
// nine ::= "CM" | "XC" | "IX"
// four ::= "CD" | "XL" | "IV"
// five ::= 'D' | 'L' | 'V'
// one ::= 'M' | 'C' | 'X' | 'I'
#include <iostream.h>
#include <string.h>
class Thousand; class Hundred; class Ten; class One;
class RNInterpreter {
public:
RNInterpreter(); // ctor for client
RNInterpreter( int ) { } // ctor for subclasses, avoids infinite loop
int interpret( char* ); // interpret() for client
virtual void interpret( char* input, int& total ) { // for internal use
int index; index = 0;
if ( ! strncmp(input, nine(), 2)) {
total += 9 * multiplier();
index += 2; }
else if ( ! strncmp(input, four(), 2)) {
total += 4 * multiplier();
index += 2; }
else {
if (input[0] == five()) {
total += 5 * multiplier();
index = 1; }
else index = 0;
for (int end = index + 3 ; index < end; index++)
if (input[index] == one())
total += 1 * multiplier();
else break; }
strcpy( input, &(input[index])); } // remove leading chars processed
protected: // cannot be pure virtual because client asks for instance
virtual char one() { } virtual char* four() { }
virtual char five() { } virtual char* nine() { }
virtual int multiplier() { }
private:
RNInterpreter* thousands; RNInterpreter* hundreds;
RNInterpreter* tens; RNInterpreter* ones;
};
class Thousand : public RNInterpreter {
public: // provide 1-arg ctor to avoid infinite loop in base class ctor
Thousand( int ) : RNInterpreter(1) { }
protected:
char one() { return 'M'; } char* four() { return ""; }
char five() { return '\0'; } char* nine() { return ""; }
int multiplier() { return 1000; }
};
class Hundred : public RNInterpreter {
public:
Hundred( int ) : RNInterpreter(1) { }
protected:
char one() { return 'C'; } char* four() { return "CD"; }
char five() { return 'D'; } char* nine() { return "CM"; }
int multiplier() { return 100; }
};
class Ten : public RNInterpreter {
public:
Ten( int ) : RNInterpreter(1) { }
protected:
char one() { return 'X'; } char* four() { return "XL"; }
char five() { return 'L'; } char* nine() { return "XC"; }
int multiplier() { return 10; }
};
class One : public RNInterpreter {
public:
One( int ) : RNInterpreter(1) { }
protected:
char one() { return 'I'; } char* four() { return "IV"; }
char five() { return 'V'; } char* nine() { return "IX"; }
int multiplier() { return 1; }
};
RNInterpreter::RNInterpreter() { // use 1-arg ctor to avoid infinite loop
thousands = new Thousand(1); hundreds = new Hundred(1);
tens = new Ten(1); ones = new One(1); }
int RNInterpreter::interpret( char* input ) {
int total; total = 0;
thousands->interpret( input, total );
hundreds->interpret( input, total );
tens->interpret( input, total );
ones->interpret( input, total );
if (strcmp(input, "")) // if input was invalid, return 0
return 0;
return total; }
void main() {
RNInterpreter interpreter;
char input[20];
cout << "Enter Roman Numeral: ";
while (cin >> input)
{
cout << " interpretation is " << interpreter.interpret(input) << endl;
cout << "Enter Roman Numeral: ";
}
}
// Enter Roman Numeral: MCMXCVI
// interpretation is 1996
// Enter Roman Numeral: MMMCMXCIX
// interpretation is 3999
// Enter Roman Numeral: MMMM
// interpretation is 0
// Enter Roman Numeral: MDCLXVIIII
// interpretation is 0
// Enter Roman Numeral: CXCX
// interpretation is 0
// Enter Roman Numeral: MDCLXVI
// interpretation is 1666
// Enter Roman Numeral: DCCCLXXXVIII
// interpretation is 888
// Purpose. Iterator design pattern
// Take traversal-of-a-collection functionality out of the collection and
// promote it to "full object status". This simplifies the collection, allows
// many traversals to be active simultaneously, and decouples collection algo-
// rithms from collection data structures.
// "Every 'container-like' class must have an iterator." [Lakos] It may seem
// like a violation of encapsulation for a Stack class to allow its users to
// access its contents directly, but John Lakos' argument is that the designer
// of a class inevitably leaves something out. Later, when users need addi-
// tional functionality, if an iterator was originally provided, they can add
// functionality with "open for extension, closed for modification". Without
// an iterator, their only recourse is to invasively customize production
// code. Below, the orginal Stack class did not include an equality operator,
// but it did include an iterator. As a result, the equality operator could
// be readily retrofitted.
// 1. Design an "iterator" class for the "container" class
// 2. Add a createIterator() member to the container class
// 3. Clients ask the container object to create an iterator object
// 4. Clients use the first(), isDone(), next(), and currentItem() protocol
#include <iostream>
using namespace std;
class Stack {
int items[10];
int sp;
public:
friend class StackIter;
Stack() { sp = -1; }
void push( int in ) { items[++sp] = in; }
int pop() { return items[sp--]; }
bool isEmpty() { return (sp == -1); }
StackIter* createIterator() const; // 2. Add a createIterator() member
};
class StackIter { // 1. Design an "iterator" class
const Stack* stk;
int index;
public:
StackIter( const Stack* s ) { stk = s; }
void first() { index = 0; }
void next() { index++; }
bool isDone() { return index == stk->sp+1; }
int currentItem() { return stk->items[index]; }
};
StackIter* Stack::createIterator() const { return new StackIter( this ); }
bool operator==( const Stack& l, const Stack& r ) {
// 3. Clients ask the container object to create an iterator object
StackIter* itl = l.createIterator();
StackIter* itr = r.createIterator();
// 4. Clients use the first(), isDone(), next(), and currentItem() protocol
for (itl->first(), itr->first(); ! itl->isDone(); itl->next(), itr->next())
if (itl->currentItem() != itr->currentItem()) break;
bool ans = itl->isDone() && itr->isDone();
delete itl; delete itr;
return ans;
}
void main( void ) {
Stack s1;
for (int i=1; i < 5; i++) s1.push(i);
Stack s2( s1 ), s3( s1 ), s4( s1 ), s5( s1 );
s3.pop(); s5.pop();
s4.push( 2 ); s5.push( 9 );
cout << "1 == 2 is "<< (s1 == s2) << endl;
cout << "1 == 3 is "<< (s1 == s3) << endl;
cout << "1 == 4 is "<< (s1 == s4) << endl;
cout << "1 == 5 is "<< (s1 == s5) << endl;
}
// 1 == 2 is 1
// 1 == 3 is 0
// 1 == 4 is 0
// 1 == 5 is 0
// Purpose. Iterator using operators instead of methods
//
// Discussion. John Lakos suggests the GOF and STL iterator interfaces are:
// error-prone (possibility of misspelling method names), clumsy, and require
// too much typing. This design uses nothing but "intuitive" operators.
// Notice also that no createIterator() was specified. The user creates these
// iterators as local variables, and no clean-up is necessary.
#include <iostream>
using namespace std;
class Stack {
int items[10];
int sp;
public:
friend class StackIter;
Stack() { sp = -1; }
void push( int in ) { items[++sp] = in; }
int pop() { return items[sp--]; }
bool isEmpty() { return (sp == -1); }
};
class StackIter {
const Stack& stk;
int index;
public:
StackIter( const Stack& s ) : stk( s ) { index = 0; }
void operator++() { index++; }
bool operator()() { return index != stk.sp+1; }
int operator*() { return stk.items[index]; }
};
bool operator==( const Stack& l, const Stack& r ) {
StackIter itl( l ), itr( r );
for ( ; itl(); ++itl, ++itr)
if (*itl != *itr) break;
return ! itl() && ! itr();
}
void main( void ) {
Stack s1; int i;
for (i=1; i < 5; i++) s1.push(i);
Stack s2( s1 ), s3( s1 ), s4( s1 ), s5( s1 );
s3.pop(); s5.pop();
s4.push( 2 ); s5.push( 9 );
cout << "1 == 2 is "<< (s1 == s2) << endl;
cout << "1 == 3 is "<< (s1 == s3) << endl;
cout << "1 == 4 is "<< (s1 == s4) << endl;
cout << "1 == 5 is "<< (s1 == s5) << endl;
}
// 1 == 2 is 1
// 1 == 3 is 0
// 1 == 4 is 0
// 1 == 5 is 0
// Purpose. Iterator using the Java interface
//
// Discussion. Java's standard collection classes have a much leaner inter-
// face. Their next() methods combine the next() and currentItem() methods.
#include <iostream>
using namespace std;
class Stack {
int items[10];
int sp;
public:
friend class StackIter;
Stack() { sp = -1; }
void push( int in ) { items[++sp] = in; }
int pop() { return items[sp--]; }
bool isEmpty() { return (sp == -1); }
StackIter* iterator() const;
};
class StackIter {
const Stack* stk;
int index;
public:
StackIter( const Stack* s ) { stk = s; index = 0; }
int next() { return stk->items[index++]; }
bool hasNext() { return index != stk->sp+1; }
};
StackIter* Stack::iterator() const { return new StackIter( this ); }
bool operator==( const Stack& l, const Stack& r ) {
StackIter* itl = l.iterator();
StackIter* itr = r.iterator();
while (itl->hasNext())
if (itl->next() != itr->next()) {
delete itl; delete itr;
return false;
}
bool ans = (! itl->hasNext()) && ( ! itr->hasNext());
delete itl; delete itr;
return ans;
}
void main( void ) {
Stack s1; int i;
for (i=1; i < 5; i++) s1.push(i);
Stack s2( s1 ), s3( s1 ), s4( s1 ), s5( s1 );
s3.pop(); s5.pop();
s4.push( 2 ); s5.push( 9 );
cout << "1 == 2 is "<< (s1 == s2) << endl;
cout << "1 == 3 is "<< (s1 == s3) << endl;
cout << "1 == 4 is "<< (s1 == s4) << endl;
cout << "1 == 5 is "<< (s1 == s5) << endl;
}
// 1 == 2 is 1
// 1 == 3 is 0
// 1 == 4 is 0
// 1 == 5 is 0
// Purpose. Simple implementation of an Iterator (uses parallel dynamic array)
//
// Discussion. Instead of having to write an involved stack-like solution to
// handle step-wise recursive descent, use a little extra memory to maintain a
// sequential representation of the original hierarchical data. The replicated
// data are not Node objects, they are lightweight pointers. The array is
// initialized using a recursive method similar to traverse(Node*).
#include <iostream>
#include <ctime>
using namespace std;
class BST {
friend class Iterator;
struct Node {
Node( int );
int value;
Node* left;
Node* rite;
};
Node* root;
int size;
void add( Node**, int );
void traverse( Node* );
public:
BST() { root = 0; size = 0; }
void add( int );
void traverse();
Iterator* createIterator() const;
};
class Iterator {
const BST* tree;
BST::Node** array;
int index;
void populateArray( BST::Node* current ) {
if (current->left) populateArray( current->left );
array[index++] = current;
if (current->rite) populateArray( current->rite );
}
public:
Iterator( const BST* s ) {
tree = s;
array = 0; index = 0;
}
~Iterator() { delete [] array; }
void first() {
delete [] array;
array = new BST::Node*[tree->size];
index = 0;
populateArray( tree->root );
index = 0;
}
void next() { index++; }
bool isDone() { return index == tree->size; }
BST::Node* currentItem() { return array[index]; }
};
void main( void ) {
srand( time( 0 ) );
BST tree;
for (int i=0; i < 20; i++) tree.add( rand() % 20 + 1 );
cout << "traverse: ";
tree.traverse();
cout << "\niterator: ";
Iterator* it = tree.createIterator();
for (it->first(); ! it->isDone(); it->next())
cout << it->currentItem()->value << ' ';
cout << "\niterator: ";
for (it->first(); ! it->isDone(); it->next())
cout << it->currentItem()->value << ' ';
cout << '\n';
}
// traverse: 1 2 3 7 8 9 9 10 11 11 13 14 14 14 15 17 18 19 19 20
// iterator: 1 2 3 7 8 9 9 10 11 11 13 14 14 14 15 17 18 19 19 20
// iterator: 1 2 3 7 8 9 9 10 11 11 13 14 14 14 15 17 18 19 19 20
BST::Node::Node( int v ) { value = v; left = rite = 0; }
void BST::add( Node** n, int v ) {
if ( ! *n) { *n = new Node( v ); size++; }
else if (v <= (*n)->value) add( &((*n)->left), v );
else add( &((*n)->rite), v );
}
void BST::add( int v ) { add( &root, v ); }
void BST::traverse() { traverse( root ); }
void BST::traverse( Node* n ) {
if (n->left) traverse( n->left );
cout << n->value << ' ';
if (n->rite) traverse( n->rite );
}
Iterator* BST::createIterator() const { return new Iterator( this ); }
// Purpose. Fairly reusable iterator for step-wise recursive descent
//
// Discussion. The Composite/Component/Leaf code is one of the previous
// Composite demos. Methods added were: Component::outputValue() and
// Composite::createIterator().
#include <iostream>
#include <vector>
using namespace std;
class Component { public:
virtual void traverse() = 0;
virtual void outputValue() { }
};
class Leaf : public Component {
int value;
public:
Leaf( int val ) { value = val; }
/*virtual*/ void traverse() { cout << value << ' '; }
/*virtual*/ void outputValue() { traverse(); }
};
class Composite : public Component {
vector<Component*> children;
public:
friend class Iterator;
void add( Component* ele ) { children.push_back( ele ); }
/*virtual*/ void traverse() {
for (int i=0; i < children.size(); i++)
children[i]->traverse();
}
Iterator* createIterator();
};
class Memento {
public:
struct MgrIdx {
MgrIdx( Composite* m=0, int i=0 ) { mgr = m; idx = i; }
Composite* mgr;
int idx;
};
void initialize( Composite* root ) {
vec.resize( 0 );
vec.push_back( MgrIdx( root, 0 ) );
}
bool isEmpty() { return vec.size() == 0; }
void push( MgrIdx ds ) { vec.push_back( ds ); }
MgrIdx top() { return vec.back(); }
MgrIdx pop() {
MgrIdx ds = vec.back();
vec.pop_back();
return ds;
}
private:
vector<MgrIdx> vec;
};
// Dependencies on actual class playing the role of "Composite":
// Composite class name, children attribute name
class Iterator {
Composite* root;
Memento memento;
bool done;
public:
Iterator( Composite* rooot ) { root = rooot; }
void first() {
memento.initialize( root );
done = false;
}
void next() {
Memento::MgrIdx ds = memento.pop();
ds.idx++;
// if (and while) you are at end-of-composite, go up
while (ds.idx == ds.mgr->children.size()) {
if (memento.isEmpty()) { done = true; return; }
ds = memento.pop();
ds.idx++;
}
memento.push( ds );
Composite* compo;
if (compo = dynamic_cast<Composite*>(ds.mgr->children[ds.idx]))
memento.push( Memento::MgrIdx( compo, 0 ) );
}
Component* currentItem() {
Memento::MgrIdx ds = memento.top();
return ds.mgr->children[ds.idx];
}
bool isDone() { return done; }
};
Iterator* Composite::createIterator() { return new Iterator( this ); }
void main( void ) {
Composite containers[4];
for (int i=0; i < 4; i++)
for (int j=0; j < 3; j++)
containers[i].add( new Leaf( i * 3 + j ) );
for (i=1; i < 4; i++) containers[0].add( &(containers[i]) );
cout << "traverse: ";
containers[0].traverse();
Iterator* it = containers[0].createIterator();
cout << "\niterator: ";
for (it->first(); ! it->isDone(); it->next())
it->currentItem()->outputValue();
cout << '\n';
cout << "iterator: ";
for (it->first(); ! it->isDone(); it->next())
it->currentItem()->outputValue();
cout << '\n';
delete it;
}
// traverse: 0 1 2 3 4 5 6 7 8 9 10 11
// iterator: 0 1 2 3 4 5 6 7 8 9 10 11
// iterator: 0 1 2 3 4 5 6 7 8 9 10 11
// Purpose. Mediator
//
// Discussion. On the left: Node objs #include <iostream.h>
// interact directly with each other,
// recursion is required, removing a class Node {
// Node is hard, and it is not possi- public:
// ble to remove the first node. On Node( int v ) { val_ = v; }
// the right: a "mediating" List class int getVal() { return val_; }
// focuses and simplifies all the ad- private:
// ministrative responsibilities, and int val_;
// the recursion (which does not scale };
// up well) has been eliminated.
class List {
#include <iostream.h> public:
List() {
class Node { for (int i=0; i < 10; i++)
public: arr_[i] = 0;
Node( int v, Node* n ) { num_ = 0;
val_ = v; }
next_ = n; void addNode( Node* n ) {
} arr_[num_++] = n;
void traverse() { }
cout << val_ << " "; void traverse() {
if (next_) for (int i=0; i < num_; i++)
next_->traverse(); cout << arr_[i]->getVal()
else << " ";
cout << endl; cout << endl;
} }
void removeNode( int v ) { void removeNode( int v ) {
Node* ptr = (Node*) 1; int i, j;
removeNode_( v, &ptr ); for (i=0; i < num_; i++)
} if (arr_[i]->getVal() == v)
private: {
int val_; for (j=i; j < num_; j++)
Node* next_; arr_[j] = arr_[j+1];
void removeNode_(int v, Node** n) { num_--;
if (val_ == v) break;
*n = next_; }
else }
{ private:
next_->removeNode_( v, n ); Node* arr_[10];
if (*n != (Node*) 1) int num_;
{ };
next_ = *n;
*n = (Node*) 1; void main( void )
} {
} List lst;
} Node one( 11 ), two( 22 );
}; Node thr( 33 ), fou( 44 );
lst.addNode( &one );
void main( void ) lst.addNode( &two );
{ lst.addNode( &thr );
Node fou( 44, 0 ); lst.addNode( &fou );
Node thr( 33, &fou ); lst.traverse();
Node two( 22, &thr ); lst.removeNode( 44 );
Node one( 11, &two ); lst.traverse();
one.traverse(); lst.removeNode( 11 );
one.removeNode( 44 ); lst.traverse();
one.traverse(); }
one.removeNode( 22 );
one.traverse(); // 11 22 33 44
} // 11 22 33
// 22 33
// 11 22 33 44
// 11 22 33
// 11 33
// Purpose. Mediator design pattern demo.
//
// Discussion. Though partitioning a system into many objects generally
// enhances reusability, proliferating interconnections tend to reduce it
// again. You can avoid this problem by capsulating the interconnections
// (i.e. the collective behavior) in a separate "mediator" object. A
// mediator is responsible for controlling and coordinating the
// interactions of a group of objects. In this example, the dialog box
// object is functioning as the mediator. Child widgets of the dialog box
// do not know, or care, who their siblings are. Whenever a simulated
// user interaction occurs in a child widget [Widget::changed()], the
// widget does nothing except "delegate" that event to its parent dialog
// box [_mediator->widgetChanged( this )].
// FileSelectionDialog::widgetChanged() encapsulates all collective
// behavior for the dialog box (it serves as the hub of communication).
// The user may choose to "interact" with a simulated: filter edit field,
// directories list, files list, or selection edit field.
#include <iostream.h>
class FileSelectionDialog;
class Widget {
public:
Widget( FileSelectionDialog* mediator, char* name ) {
_mediator = mediator;
strcpy( _name, name); }
virtual void changed();
virtual void updateWidget() = 0;
virtual void queryWidget() = 0;
protected:
char _name[20];
private:
FileSelectionDialog* _mediator;
};
class List : public Widget {
public:
List( FileSelectionDialog* dir, char* name ) : Widget( dir, name ) { }
void queryWidget() { cout << " " << _name << " list queried" << endl; }
void updateWidget() { cout << " " << _name << " list updated" << endl; }
};
class Edit : public Widget {
public:
Edit( FileSelectionDialog* dir, char* name ): Widget( dir, name ) { }
void queryWidget() { cout << " " << _name << " edit queried" << endl; }
void updateWidget() { cout << " " << _name << " edit updated" << endl; }
};
class FileSelectionDialog {
public:
enum Widgets { FilterEdit, DirList, FileList, SelectionEdit };
FileSelectionDialog() {
_components[FilterEdit] = new Edit( this, "filter" );
_components[DirList] = new List( this, "dir" );
_components[FileList] = new List( this, "file" );
_components[SelectionEdit] = new Edit( this, "selection" ); }
virtual ~FileSelectionDialog();
void handleEvent( int which ) {
_components[which]->changed(); }
virtual void widgetChanged( Widget* theChangedWidget ) {
if (theChangedWidget == _components[FilterEdit] ) {
_components[FilterEdit]-> queryWidget();
_components[DirList]-> updateWidget();
_components[FileList]-> updateWidget();
_components[SelectionEdit]-> updateWidget(); }
else if (theChangedWidget == _components[DirList] ) {
_components[DirList]-> queryWidget();
_components[FileList]-> updateWidget();
_components[FilterEdit]-> updateWidget();
_components[SelectionEdit]-> updateWidget(); }
else if (theChangedWidget == _components[FileList] ) {
_components[FileList]-> queryWidget();
_components[SelectionEdit]-> updateWidget(); }
else if (theChangedWidget == _components[SelectionEdit] ) {
_components[SelectionEdit]-> queryWidget();
cout << " file opened" << endl; } }
private:
Widget* _components[4];
};
FileSelectionDialog::~FileSelectionDialog() {
for (int i=0; i < 3; i++)
delete _components[i]; }
void Widget::changed() {
_mediator->widgetChanged( this ); }
void main() {
FileSelectionDialog fileDialog;
int i;
cout << "Exit[0], Filter[1], Dir[2], File[3], Selection[4]: ";
cin >> i;
while (i)
{
fileDialog.handleEvent( i-1 );
cout << "Exit[0], Filter[1], Dir[2], File[3], Selection[4]: ";
cin >> i;
}
}
// Exit[0], Filter[1], Dir[2], File[3], Selection[4]: 1
// filter edit queried
// dir list updated
// file list updated
// selection edit updated
// Exit[0], Filter[1], Dir[2], File[3], Selection[4]: 2
// dir list queried
// file list updated
// filter edit updated
// selection edit updated
// Exit[0], Filter[1], Dir[2], File[3], Selection[4]: 3
// file list queried
// selection edit updated
// Exit[0], Filter[1], Dir[2], File[3], Selection[4]: 4
// selection edit queried
// file opened
// Exit[0], Filter[1], Dir[2], File[3], Selection[4]: 3
// file list queried
// selection edit updated
// Purpose. Memento design pattern
// 1. Assign the roles of "caretaker" and "originator"
// 2. Create a "memento" class and declare the originator a friend
// 3. Caretaker knows when to "check point" the originator
// 4. Originator creates a memento and copies its state to the memento
// 5. Caretaker holds on to (but cannot peek in to) the memento
// 6. Caretaker knows when to "roll back" the originator
// 7. Originator reinstates itself using the saved state in the memento
#include <iostream> #include <string> using namespace std;
class Memento { // 2. Create a "memento" class and
friend class Stack; // declare the originator a friend
int *items, num;
Memento( int* arr, int n ) {
items = new int[num = n];
for (int i=0; i < num; i++) items[i] = arr[i]; }
public:
~Memento() { delete items; }
};
class Stack { // 1. Stack is the "originator"
int items[10], sp;
public:
Stack() { sp = -1; }
void push( int in ) { items[++sp] = in; }
int pop() { return items[sp--]; }
bool isEmpty() { return sp == -1; }
// 4. Originator creates a memento and copies its state to the memento
Memento* checkPoint() {
return new Memento( items, sp+1 );
}
// 7. Originator reinstates itself using the saved state in the memento
void rollBack( Memento* m ) {
sp = m->num-1;
for (int i=0; i < m->num; i++) items[i] = m->items[i];
}
friend ostream& operator<< ( ostream& os, const Stack& s ) {
string buf( "[ " );
for (int i=0; i < s.sp+1; i++) { buf += s.items[i]+48; buf += ' '; }
buf += ']';
return os << buf; // stack is [ 0 1 2 3 4 ]
} }; // stack is [ 0 1 2 3 4 5 6 7 8 9 ]
// popping stack: 9 8 7 6 5 4 3 2 1 0
// 1. main() is the "caretaker" // stack is [ ]
void main( void ) { // second is [ 0 1 2 3 4 5 6 7 8 9 ]
Stack s; // first is [ 0 1 2 3 4 ]
for (int i=0; i < 5; i++) s.push( i ); // popping stack: 4 3 2 1 0
cout << "stack is " << s << endl;
Memento* first = s.checkPoint(); // 3. Caretaker knows when to save
for (i=5; i < 10; i++) s.push( i ); // 5. Caretaker holds on to memento
cout << "stack is " << s << endl;
Memento* second = s.checkPoint(); // 3. Caretaker knows when to save
cout << "popping stack: "; // 5. Caretaker holds on to memento
while ( ! s.isEmpty()) cout << s.pop() << ' '; cout << endl;
cout << "stack is " << s << endl;
s.rollBack( second ); // 6. Caretaker knows when to undo
cout << "second is " << s << endl;
s.rollBack( first ); // 6. Caretaker knows when to undo
cout << "first is " << s << endl;
cout << "popping stack: ";
while ( ! s.isEmpty()) cout << s.pop() << ' '; cout << endl;
delete first; delete second;
}
// Purpose. Memento design pattern
//
// Discussion. A memento is an object that stores a snapshot of the
// internal state of another object. It can be leveraged to support
// multi-level undo of the Command pattern. In this example, before a
// command is run against the Number object, Number's current state is
// saved in Command's static memento history list, and the command itself
// is saved in the static command history list. Undo() simply "pops" the
// memento history list and reinstates Number's state from the memento.
// Redo() "pops" the command history list. Note that Number's encapsula-
// tion is preserved, and Memento is wide open to Number.
#include <iostream.h>
class Number;
class Memento {
public:
Memento( int val ) { _state = val; }
private:
friend class Number; // not essential, but p287 suggests this
int _state;
};
class Number {
public:
Number( int value ) { _value = value; }
void dubble() { _value = 2 * _value; }
void half() { _value = _value / 2; }
int getValue() { return _value; }
Memento* createMemento() { return new Memento( _value ); }
void reinstateMemento( Memento* mem ) { _value = mem->_state ; }
private:
int _value;
};
class Command {
public:
typedef void (Number::* Action)();
Command( Number* receiver, Action action ) {
_receiver = receiver;
_action = action; }
virtual void execute() {
_mementoList[_numCommands] = _receiver->createMemento();
_commandList[_numCommands] = this;
if (_numCommands > _highWater) _highWater = _numCommands;
_numCommands++;
(_receiver->*_action)(); }
static void undo() {
if (_numCommands == 0) {
cout << "*** Attempt to run off the end!! ***" << endl;
return; }
_commandList[_numCommands-1]->_receiver->
reinstateMemento( _mementoList[_numCommands-1] );
_numCommands--; }
void static redo() {
if (_numCommands > _highWater) {
cout << "*** Attempt to run off the end!! ***" << endl;
return; }
(_commandList[_numCommands]->_receiver->
*(_commandList[_numCommands]->_action))();
_numCommands++; }
protected:
Number* _receiver;
Action _action;
static Command* _commandList[20];
static Memento* _mementoList[20];
static int _numCommands;
static int _highWater;
};
Command* Command::_commandList[];
Memento* Command::_mementoList[];
int Command::_numCommands = 0;
int Command::_highWater = 0;
void main() {
int i;
cout << "Integer: ";
cin >> i;
Number* object = new Number(i);
Command* commands[3];
commands[1] = new Command( object, &Number::dubble );
commands[2] = new Command( object, &Number::half );
cout << "Exit[0], Double[1], Half[2], Undo[3], Redo[4]: ";
cin >> i;
while (i)
{
if (i == 3)
Command::undo();
else if (i == 4)
Command::redo();
else
commands[i]->execute();
cout << " " << object->getValue() << endl;
cout << "Exit[0], Double[1], Half[2], Undo[3], Redo[4]: ";
cin >> i;
}
}
// Integer: 11
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 2
// 5
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 1
// 10
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 2
// 5
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3
// 10
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3
// 5
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3
// 11
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3
// *** Attempt to run off the end!! ***
// 11
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4
// 5
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4
// 10
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4
// 5
// Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4
// *** Attempt to run off the end!! ***
// 5
// Purpose. Observer class Obs;
//
// Discussion. On the left: Subject class Subject {
// has hard-wired the number and type public:
// of "dependent" objects, the compil- Subject();
// er must have the declaration of the void attach( Obs* );
// concrete Obs classes to compile void setVal( int );
// Subject's decl, the Obs classes ex- int getVal();
// ercise no reuse of i/f or impl, and void notify();
// Subject "pushes" updates to the Obs private:
// objects. On the right: Subject is Obs* obs_[10];
// decoupled from the number, type, int num_, val_;
// and declaration of concrete Obs };
// subclasses; the Obs objects accept
// polymorphism; and Subject broad- class Obs { public:
// casts that a change has occurred virtual void update() = 0;
// followed by Obs objects requesting protected:
// just the info that they want. Subject* sub_;
int div_;
class DivObs { public: };
DivObs( int ); class DivObs : public Obs { public:
void update( int ); DivObs( Subject*, int );
private: void update();
int div_; };
}; class ModObs : public Obs { public:
class ModObs { public: ModObs( Subject*, int );
ModObs( int ); void update();
void update( int ); };
private:
int div_; Subject::Subject() { num_ = 0; }
}; int Subject::getVal() { return val_; }
void Subject::attach( Obs* o ) {
class Subject { obs_[num_++] = o; }
public: void Subject::setVal( int v ) {
Subject(); val_ = v; notify(); }
void setVal( int ); void Subject::notify() {
private: for (int i=0; i < num_; i++)
int val_; obs_[i]->update(); }
DivObs div_;
ModObs mod_; DivObs::DivObs( Subject* s, int d ) {
}; sub_ = s; div_ = d;
sub_->attach( this ); }
Subject::Subject() : div_(4), mod_(3) void DivObs::update() {
{ } int v = sub_->getVal();
void Subject::setVal( int v ) { cout << v << " div " << div_
val_ = v; << " is " << v / div_ << endl; }
div_.update( val_ ); ModObs::ModObs( Subject* s, int d ) {
mod_.update( val_ ); } sub_ = s; div_ = d;
sub_->attach( this ); }
DivObs::DivObs( int d ) { div_ = d; } void ModObs::update() {
void DivObs::update( int v ) { int v = sub_->getVal();
cout << v << " div " << div_ cout << v << " mod " << div_
<< " is " << v / div_ << endl; } << " is " << v % div_ << endl; }
ModObs::ModObs( int d ) { div_ = d; }
void ModObs::update( int v ) { void main( void )
cout << v << " mod " << div_ {
<< " is " << v % div_ << endl; } Subject subj;
DivObs divObs1( &subj, 4 );
void main( void ) DivObs divObs2( &subj, 3 );
{ ModObs modObs3( &subj, 3 );
Subject subj; subj.setVal( 14 );
subj.setVal( 14 ); }
}
// 14 div 4 is 3
// 14 div 4 is 3 // 14 div 3 is 4
// 14 mod 3 is 2 // 14 mod 3 is 2
// Purpose. Observer design pattern
// 1. Model the "independent" functionality with a "subject" abstraction
// 2. Model the "dependent" functionality with "observer" hierarchy
// 3. The Subject is coupled only to the Observer base class
// 4. Observers register themselves with the Subject
// 5. The Subject broadcasts events to all registered Observers
// 6. Observers "pull" the information they need from the Subject
// 7. Client configures the number and type of Observers
#include <iostream>
#include <vector>
using namespace std;
class Subject { // 1. "independent" functionality
vector<class Observer*> views; // 3. Coupled only to "interface"
int value;
public:
void attach( Observer* obs ) { views.push_back( obs ); }
void setVal( int val ) { value = val; notify(); }
int getVal() { return value; }
void notify();
};
class Observer { // 2. "dependent" functionality
Subject* model;
int denom;
public:
Observer( Subject* mod, int div ) {
model = mod; denom = div;
// 4. Observers register themselves with the Subject
model->attach( this );
}
virtual void update() = 0;
protected:
Subject* getSubject() { return model; }
int getDivisor() { return denom; }
};
void Subject::notify() { // 5. Publisher broadcasts
for (int i=0; i < views.size(); i++) views[i]->update();
}
class DivObserver : public Observer { public:
DivObserver( Subject* mod, int div ) : Observer(mod,div) { }
void update() { // 6. "Pull" information of interest
int v = getSubject()->getVal(), d = getDivisor();
cout << v << " div " << d << " is " << v / d << '\n';
} };
class ModObserver : public Observer { public:
ModObserver( Subject* mod, int div ) : Observer(mod,div) { }
void update() {
int v = getSubject()->getVal(), d = getDivisor();
cout << v << " mod " << d << " is " << v % d << '\n';
} };
void main( void ) {
Subject subj;
DivObserver divObs1( &subj,4 ); // 7. Client configures the number and
DivObserver divObs2( &subj,3 ); // type of Observers
ModObserver modObs3( &subj,3 );
subj.setVal( 14 );
}
// 14 div 4 is 3
// 14 div 3 is 4
// 14 mod 3 is 2
// Purpose. Observer design pattern, class inheritance vs type inheritance
// SensorSystem is the "subject". Lighting, Gates, and Surveillance are the
// "views". The subject is only coupled to the "abstraction" of AlarmListener.
// An object's class defines how the object is implemented. In contrast, an
// object's type only refers to its interface. Class inheritance defines an
// object's implementation in terms of another object's implementation. Type
// inheritance describes when an object can be used in place of another.
// [GoF, pp13-17]
#include <iostream>
#include <vector>
using namespace std;
class AlarmListener { public: virtual void alarm() = 0; };
class SensorSystem {
vector<AlarmListener*> listeners;
public:
void attach( AlarmListener* al ) { listeners.push_back( al ); }
void soundTheAlarm() {
for (int i=0; i < listeners.size(); i++)
listeners[i]->alarm();
} };
class Lighting : public AlarmListener {
public: /*virtual*/ void alarm() { cout << "lights up" << '\n'; }
};
class Gates : public AlarmListener {
public: /*virtual*/ void alarm() { cout << "gates close" << '\n'; }
};
class CheckList {
virtual void localize() { cout << " establish a perimeter" << '\n'; }
virtual void isolate() { cout << " isolate the grid" << '\n'; }
virtual void identify() { cout << " identify the source" << '\n'; }
public:
void byTheNumbers() { // Template Method design pattern
localize();
isolate();
identify();
} };
// class inheri. // type inheritance
class Surveillance : public CheckList, public AlarmListener {
/*virtual*/ void isolate() { cout << " train the cameras" << '\n'; }
public:
/*virtual*/ void alarm() {
cout << "Surveillance - by the numbers:" << '\n';
byTheNumbers();
} };
void main( void ) {
SensorSystem ss;
ss.attach( &Gates() );
ss.attach( &Lighting() );
ss.attach( &Surveillance() );
ss.soundTheAlarm();
}
// gates close
// lights up
// Surveillance - by the numbers:
// establish a perimeter
// train the cameras
// identify the source
// Purpose. Observer and Mediator demo
//
// Observer - 1. Sender is coupled to a Receiver interface
// 2. Receivers register with Sender
// 3. Sender broadcasts (in the blind) to all Receivers
//
// Mediator - 4. Sender(s) has handle to Mediator
// 5. Mediator has handle to Receiver(s)
// 6. Sender(s) sends to Mediator
// 7. Mediator sends to Receiver(s)
#include <iostream>
#include <vector>
using namespace std;
void gotoxy( int, int );
class Observer { public: virtual void update( int ) = 0; };
class Mediator {
vector<Observer*> groups[3]; // 1. Sender is coupled to an interface
public:
enum Message { ODD, EVEN, THREE }; // 1. Sender is coupled to an interface
void attach( Observer* o, Message type ) { groups[type].push_back( o ); }
void disseminate( int num ) {
if (num % 2 == 1) // odd // 3,7. Sender/Mediator broadcasts
for (int i=0; i < groups[0].size(); i++) groups[0][i]->update(num);
else // even
for (int i=0; i < groups[1].size(); i++) groups[1][i]->update(num);
if (num % 3 == 0) // /3
for (int i=0; i < groups[2].size(); i++) groups[2][i]->update(num);
} };
class OddObserver : public Observer {
int col, row;
public:
OddObserver( Mediator& med, int c ) {
col = c; row = 3;
gotoxy( col, 1 ); cout << "Odd";
gotoxy( col, 2 ); cout << "---";
med.attach( this, Mediator::ODD ); // 2,5. Receivers register with Sender
}
void update( int num ) { gotoxy( col, row++ ); cout << num; }
};
class EvenObserver : public Observer {
int col, row;
public:
EvenObserver( Mediator& med, int c ) {
col = c; row = 3;
gotoxy( col, 1 ); cout << "/2";
gotoxy( col, 2 ); cout << "--";
med.attach( this, Mediator::EVEN );
}
void update( int num ) { gotoxy( col, row++ ); cout << num; }
};
class ThreeObserver : public Observer {
int col, row;
public:
ThreeObserver( Mediator& med, int c ) {
col = c; row = 3;
gotoxy( col, 1 ); cout << "/3";
gotoxy( col, 2 ); cout << "--";
med.attach( this, Mediator::THREE );
}
void update( int num ) { gotoxy( col, row++ ); cout << num; }
};
class Publisher { public: // 6. Sender sends to Mediator
Publisher( Mediator& med ) { for (int i=1; i < 10; i++) med.disseminate(i); }
};
void main( void ) {
Mediator mediator;
OddObserver( mediator, 1 );
EvenObserver( mediator, 11 );
ThreeObserver( mediator, 21 );
Publisher producer( mediator ); // 4. Sender has handle to Mediator
}
// Odd /2 /3
// --- -- --
// 1 2 3
// 3 4 6
// 5 6 9
// 7 8
// 9
// Purpose. TypedMessage - embellished Observer, decoupled messaging
//
// Messages inherit from TypedMessage<self>
// Message listeners inherit from many Message::Handlers
// Application tells message to publish/broadcast/notify
// Messages are the subject (receive registrations from subscribers)
// Subsystems are the observers (receive broadcast messages)
// TypedMessage accomodates everything: registration, containment, and
// notification of observers
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <class T>
class TypedMessage {
static vector<Handler*> registry;
public:
class Handler {
public:
Handler() { TypedMessage<T>::registerHandler( this ); }
virtual void handleEvent( const T* t ) = 0;
};
void notify() {
for (int i=0; i < registry.size(); i++)
registry.at(i)->handleEvent( (T*)this );
}
static void registerHandler( Handler* h ) { registry.push_back( h ); }
};
class On : public TypedMessage<On> {
string comment;
public:
On( string str ) { comment = str; }
void start() const { cout << "OnEvent.start - " << comment << '\n'; }
};
vector<TypedMessage<On>::Handler*> TypedMessage<On>::registry;
class Off : public TypedMessage<Off> {
string comment;
public:
Off( string str ) { comment = str; }
void stop() const { cout << "OffEvent.stop - " << comment << '\n'; }
};
vector<TypedMessage<Off>::Handler*> TypedMessage<Off>::registry;
class MasterConsole : public On::Handler, public Off::Handler { public:
void handleEvent( const On* msg ) {
cout << "MasterConsole - "; msg->start(); }
void handleEvent( const Off* msg ) {
cout << "MasterConsole - "; msg->stop(); }
};
class PowerMonitor : public On::Handler { public:
void handleEvent( const On* msg ) {
cout << "PowerMonitor - "; msg->start(); }
};
void main( void ) {
MasterConsole mc;
PowerMonitor pm;
On oneEvent( "lights" ); Off thrEvent( "elevators" );
On twoEvent( "hvac" ); Off fouEvent( "frontDoor" );
oneEvent.notify(); twoEvent.notify();
thrEvent.notify(); fouEvent.notify();
}
// MasterConsole - OnEvent.start - lights
// PowerMonitor - OnEvent.start - lights
// MasterConsole - OnEvent.start - hvac
// PowerMonitor - OnEvent.start - hvac
// MasterConsole - OffEvent.stop - elevators
// MasterConsole - OffEvent.stop - frontDoor
// Purpose. State #include <iostream.h>
//
// Discussion. The boss's behavior is class Boss {
// "morphing" radically as a function public:
// of his mood. Operations have large friend class Disposition;
// "case" constructs that depend on Boss();
// this "state" attribute. Like large void decide();
// procedures, large conditional stmts void direct();
// are undesirable. They're monolith- private:
// ic, and tend to make maintenance Disposition* moods_[2];
// very difficult. The State pattern int current_;
// models individual states with de- };
// rived classes of an inheritance
// hierarchy, and front-ends this class Disposition {
// hierarchy with an "interface" public:
// object that knows its "current" virtual void decide( Boss* ) = 0;
// state. This partitions and local- virtual void direct( Boss* ) = 0;
// izes all state-specific responsi- protected:
// bilities; allowing for a cleaner void toggle( Boss* b ) {
// implementation of dynamic behavior b->current_ = ! b->current_; }
// that must change as internal state };
// changes.
class DilbertZone :
class Boss { public Disposition { public:
public: void decide( Boss* b ) {
Boss() { cout << "Eenie, meenie, mynie,";
mood_ = DilbertZone; cout << " moe.\n"; toggle(b); }
} void direct( Boss* b ) {
void decide() { cout << "My whim - you're";
if (mood_ == DilbertZone) { cout << " nightmare.\n";
cout << "Eenie, meenie,"; toggle(b); }
cout << " mynie, moe.\n"; };
} class Sunny :
else if (mood_ == Sunny) { public Disposition { public:
cout << "You need it - you"; void decide( Boss* b ) {
cout << " got it.\n"; cout << "You need it - you got";
} cout << " it.\n"; toggle(b); }
toggle(); void direct( Boss* b ) {
} cout << "Follow me.\n";
void direct() { toggle(b); }
if (mood_ == DilbertZone) { };
cout << "My whim - you're";
cout << " nightmare.\n"; Boss::Boss() {
} moods_[0] = new DilbertZone;
else if (mood_ == Sunny) moods_[1] = new Sunny;
cout << "Follow me.\n"; current_ = 0; }
toggle(); void Boss::decide() {
} moods_[current_]->decide( this ); }
private: void Boss::direct() {
enum Disposition { Sunny, moods_[current_]->direct( this ); }
DilbertZone};
Disposition mood_; void main( void )
void toggle() { mood_ = ! mood_; } {
}; Boss ph;
for (int i=0; i < 2; i++) {
void main( void ) ph.decide();
{ ph.decide();
Boss ph; ph.direct(); }
for (int i=0; i < 2; i++) }
{ // Eenie, meenie, mynie, moe.
ph.decide(); // You need it - you got it.
ph.decide(); // My whim - you're nightmare.
ph.direct(); // You need it - you got it.
} // Eenie, meenie, mynie, moe.
} // Follow me.
// Purpose. State design pattern - an FSM with two states and
// two events (distributed transition logic - logic in the
// derived state classes)
#include <iostream> \ Event on off
using namespace std; State \ ------- -------
ON nothing OFF
class Machine { OFF ON nothing
class State* current;
public:
Machine();
void setCurrent( State* s ) { current = s; }
void on();
void off();
};
class State {
public:
virtual void on( Machine* m ) { cout << " already ON\n"; }
virtual void off( Machine* m ) { cout << " already OFF\n"; }
};
void Machine::on() { current->on( this ); }
void Machine::off() { current->off( this ); }
class ON : public State {
public:
ON() { cout << " ON-ctor "; };
~ON() { cout << " dtor-ON\n"; };
void off( Machine* m );
};
class OFF : public State {
public:
OFF() { cout << " OFF-ctor "; };
~OFF() { cout << " dtor-OFF\n"; };
void on( Machine* m ) {
cout << " going from OFF to ON";
m->setCurrent( new ON() );
delete this;
}
};
void ON::off( Machine* m ) {
cout << " going from ON to OFF";
m->setCurrent( new OFF() );
delete this;
}
Machine::Machine() { current = new OFF(); cout << '\n'; }
void main( void ) {
void (Machine::*ptrs[])() = { Machine::off, Machine::on };
Machine fsm;
int num;
while (1) {
cout << "Enter 0/1: ";
cin >> num;
(fsm.*ptrs[num])();
} }
// OFF-ctor
// Enter 0/1: 0
// already OFF
// Enter 0/1: 1
// going from OFF to ON ON-ctor dtor-OFF
// Enter 0/1: 1
// already ON
// Enter 0/1: 0
// going from ON to OFF OFF-ctor dtor-ON
// Enter 0/1: 1
// going from OFF to ON ON-ctor dtor-OFF
// Enter 0/1: 0
// going from ON to OFF OFF-ctor dtor-ON
// Enter 0/1: 0
// already OFF
// Enter 0/1:
// Purpose. State design pattern - an FSM with two states and two events
// (distributed transition logic - logic in the derived state classes)
// State\Event Suck up money Drive through
//
// RedLight you're a you're
// victim, dead,
// maybe change change to RED
// to GREEN
//
// GreenLight you're an you're free
// idiot but you're
// still a victim,
// change to RED
#include <iostream>
#include <ctime>
using namespace std;
class FSM {
class State* current;
public:
FSM();
void setCurrent( State* s ) { current = s; }
void suckUpMoney( int );
void carDrivesThrough();
};
class State {
int total;
protected:
int getTotal() { return total; }
public:
State() { total = 0; }
virtual void suckUpMoney( int in, FSM* fsm ) {
total += in;
cout << "total is " << total << '\n';
}
virtual void carDrivesThrough( FSM* fsm ) = 0;
};
class GreenLight : public State {
public:
GreenLight() { cout << "GREEN light\n"; }
void suckUpMoney( int in, FSM* fsm ) {
cout << " You're an idiot, ";
State::suckUpMoney( in, fsm );
}
void carDrivesThrough( FSM* fsm );
};
class RedLight : public State {
public:
RedLight() { cout << "RED light\n"; }
void suckUpMoney( int in, FSM* fsm ) {
cout << " ";
State::suckUpMoney( in, fsm );
if (getTotal() >= 50) {
fsm->setCurrent( new GreenLight );
delete this;
} }
void carDrivesThrough( FSM* fsm ) {
cout << "Sirens!! Heat-seeking missile!! Confiscate net worth!!\n";
fsm->setCurrent( new RedLight );
delete this;
} };
FSM::FSM() {
current = new RedLight();
}
void FSM::suckUpMoney( int in ) {
current->suckUpMoney( in, this );
}
void FSM::carDrivesThrough() {
current->carDrivesThrough( this );
}
void GreenLight::carDrivesThrough( FSM* fsm ) {
cout << "Good-bye sucker!!\n";
fsm->setCurrent( new RedLight );
delete this;
}
int getCoin() {
static int choices[3] = { 5, 10, 25 };
return choices[rand() % 3];
}
void main( void ) {
srand( time(0) );
FSM fsm;
int ans;
while (true) {
cout << " Shell out (1), Drive thru (2), Exit (0): ";
cin >> ans;
if (ans == 1) fsm.suckUpMoney( getCoin() );
else if (ans == 2) fsm.carDrivesThrough();
else break;
} }
// Purpose. State demo (centralized transition logic - logic in the FSM)
//
// Discussion. Who defines the state transitions? The State pattern does not
// specify which participant defines the criteria for state transitions. The
// logic can be implemented entirely in the Context (FSM). It is generally
// more flexible and appropriate, however, to let the State subclasses them-
// selves specify their successor state and when to make the transition. This
// requires adding an interface to the Context that lets State objects set the
// Context's current state explicitly. A disadvantage of decentralization is
// that State subclasses will be coupled to other sibling subclasses. [GOF308]
#include <iostream.h>
class FSMstate { public:
virtual void on() { cout << "undefined combo" << endl; }
virtual void off() { cout << "undefined combo" << endl; }
virtual void ack() { cout << "undefined combo" << endl; } };
class FSM {
public:
FSM();
void on() { states[current]->on(); current = next[current][0]; }
void off() { states[current]->off(); current = next[current][1]; }
void ack() { states[current]->ack(); current = next[current][2]; }
private:
FSMstate* states[3];
int current;
int next[3][3];
};
class A : public FSMstate { public:
void on() { cout << "A, on ==> A" << endl; }
void off() { cout << "A, off ==> B" << endl; }
void ack() { cout << "A, ack ==> C" << endl; }
};
class B : public FSMstate { public:
void off() { cout << "B, off ==> A" << endl; }
void ack() { cout << "B, ack ==> C" << endl; }
};
class C : public FSMstate { public:
void ack() { cout << "C, ack ==> B" << endl; }
};
FSM::FSM() {
states[0] = new A; states[1] = new B; states[2] = new C;
current = 1;
next[0][0] = 0; next[0][1] = 1; next[0][2] = 2;
next[1][0] = 1; next[1][1] = 0; next[1][2] = 2;
next[2][0] = 2; next[2][1] = 2; next[2][2] = 1; }
enum Message { On, Off, Ack };
Message messageArray[10] = { On,Off,Off,Ack,Ack,Ack,Ack,On,Off,Off };
void main( void ) {
FSM fsm;
for (int i = 0; i < 10; i++) {
if (messageArray[i] == On) fsm.on();
else if (messageArray[i] == Off) fsm.off();
else if (messageArray[i] == Ack) fsm.ack(); }
}
// undefined combo // B, ack ==> C
// B, off ==> A // C, ack ==> B
// A, off ==> B // undefined combo
// B, ack ==> C // B, off ==> A
// C, ack ==> B // A, off ==> B
// Purpose. Strategy #include <iostream.h>
// #include <stdlib.h>
// Discussion. The class Stat has a #include <time.h>
// Bubble sort algorithm hard-wired in
// it. It would be nice if the choice class SortImp;
// of algorithm were configurable.
// The Strategy pattern suggests "de- class Stat {
// fine a family of algo's, encapsu- public:
// late each one, and make them inter- Stat();
// changeable" via an abstract base void upGrade();
// class. void downGrade();
void readVector( int[], int );
class Stat { /* Bubble sort */ int getMin() { return min_; }
public: int getMax() { return max_; }
void readVector( int v[], int n ) { int getMed() { return med_; }
sort_( v, n ); private:
min_ = v[0]; max_ = v[n-1]; int min_, max_, med_;
med_ = v[n/2]; } SortImp* imp_;
int getMin() { return min_; } };
int getMax() { return max_; }
int getMed() { return med_; } class SortImp { public:
private: virtual void sort( int[], int ) = 0;
int min_, max_, med_; };
void sort_( int v[], int n ) {
for (int i=n-1; i > 0; i--) class SortBubble : public SortImp {
for (int j=0; j < i; j++) public:
if (v[j] > v[j+1]) { void sort( int v[], int n );
int t = v[j]; };
v[j] = v[j+1];
v[j+1] = t; } class SortShell : public SortImp {
cout << "Bubble: "; public:
for (int k=0; k < n; k++) void sort( int v[], int n );
cout << v[k] << ' '; };
cout << endl;
} #include "strategy2.inc"
};
Stat::Stat() { imp_ = new SortBubble; }
void main( void ) void Stat::upGrade() { delete imp_;
{ imp_ = new SortShell; }
const int NUM = 9; void Stat::downGrade() { delete imp_;
int array[NUM]; imp_ = new SortBubble; }
time_t t; void Stat::readVector(int v[], int n) {
srand((unsigned) time(&t)); imp_->sort( v, n );
cout << "Vector: "; min_ = v[0]; max_ = v[n-1];
for (int i=0; i < NUM; i++) { med_ = v[n/2]; }
array[i] = rand() % 9 + 1;
cout << array[i] << ' '; } void main( void )
cout << endl; {
const int NUM = 9;
Stat obj; int array[NUM];
obj.readVector( array, NUM ); time_t t;
cout << "min is " << obj.getMin() srand((unsigned) time(&t));
<< ", max is " << obj.getMax() cout << "Vector: ";
<< ", median is " << obj.getMed() for (int i=0; i < NUM; i++) {
<< endl; array[i] = rand() % 9 + 1;
} cout << array[i] << ' '; }
cout << endl;
/***** current implementation *****/
// Vector: 6 9 9 8 6 5 7 9 2 Stat obj;
// Bubble: 2 5 6 6 7 8 9 9 9 obj.upGrade();
// min is 2, max is 9, median is 7 obj.readVector( array, NUM );
/*** an upgraded implementation ***/ cout << "min is " << obj.getMin()
// Vector: 4 8 6 4 6 7 4 7 2 << ", max is " << obj.getMax()
// Shell: 2 4 4 4 6 6 7 7 8 << ", median is " << obj.getMed()
// min is 2, max is 8, median is 6 << endl;
}
// Purpose. Strategy (template #include <iostream>
// approach) #include <cstdlib>
// A template can be used to configure #include <ctime>
// a client with a Strategy. This using namespace std;
// technique is appropriate if: 1) the
// Strategy can be selected at com- template<class STRATEGY>
// pile-time, and 2) it does not have class Stat {
// to be changed at run-time. With a public:
// template, there is no need to spe- void readVector( int v[], int n ) {
// cify the interface in a SortImp imp_.sort( v, n );
// base class. The Stat class now has min_ = v[0]; max_ = v[n-1];
// an instance of the sort object, in- med_ = v[n/2]; }
// stead of a ptr to the base class. int getMin() { return min_; }
// The inheritance approach offers int getMax() { return max_; }
// more options and expressiveness. int getMed() { return med_; }
// The template approach offers mildly private:
// better efficiency. int min_, max_, med_;
STRATEGY imp_;
class Stat { /* Bubble sort */ };
public:
void readVector( int v[], int n ) { class SortBubble {
sort_( v, n ); public:
min_ = v[0]; max_ = v[n-1]; void sort( int v[], int n );
med_ = v[n/2]; } };
int getMin() { return min_; }
int getMax() { return max_; } class SortShell {
int getMed() { return med_; } public:
private: void sort( int v[], int n );
int min_, max_, med_; };
void sort_( int v[], int n ) {
for (int i=n-1; i > 0; i--) #include "strategy2.inc"
for (int j=0; j < i; j++)
if (v[j] > v[j+1]) { void main( void ) {
int t = v[j]; const int NUM = 9;
v[j] = v[j+1]; int array[NUM];
v[j+1] = t; } time_t t;
cout << "Bubble: "; srand((unsigned) time(&t));
for (int k=0; k < n; k++) cout << "Vector: ";
cout << v[k] << ' '; for (int i=0; i < NUM; i++) {
cout << endl; array[i] = rand() % 9 + 1;
} cout << array[i] << ' '; }
}; cout << endl;
void main( void ) { Stat<SortBubble> obj;
const int NUM = 9; obj.readVector( array, NUM );
int array[NUM]; cout << "min is " << obj.getMin()
time_t t; << ", max is " << obj.getMax()
srand((unsigned) time(&t)); << ", median is " << obj.getMed()
cout << "Vector: "; << endl;
for (int i=0; i < NUM; i++) {
array[i] = rand() % 9 + 1; Stat<SortShell> two;
cout << array[i] << ' '; } two.readVector( array, NUM );
cout << endl; cout << "min is " << two.getMin()
<< ", max is " << two.getMax()
Stat obj; << ", median is " << two.getMed()
obj.readVector( array, NUM ); << endl;
cout << "min is " << obj.getMin() }
<< ", max is " << obj.getMax()
<< ", median is " << obj.getMed() // Vector: 3 5 4 9 7 1 4 9 2
<< endl; // Bubble: 1 2 3 4 4 5 7 9 9
} // min is 1, max is 9, median is 4
// Shell: 1 2 3 4 4 5 7 9 9
// Vector: 6 9 9 8 6 5 7 9 2 // min is 1, max is 9, median is 4
// Bubble: 2 5 6 6 7 8 9 9 9
// min is 2, max is 9, median is 7
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Here are the same examples NOT side-by-side, and with the
// #include "strategy2.inc" removed.
// Strategy pattern - before
//
// The class Stat has a Bubble sort algorithm hard-wired in it.
// It would be nice if the choice of algorithm were configurable.
// The Strategy pattern suggests "define a family of algorithms,
// encapsulate the hierarchy, and make them interchangeable" via
// an abstract base class.
#include <iostream>
using std::cout;
class Stat {
public:
void readVector( int v[], int n ) {
sort( v, n );
m_min = v[0];
m_max = v[n-1];
m_median = v[n/2];
}
int getMin() { return m_min; }
int getMax() { return m_max; }
int getMedian() { return m_median; }
private:
int m_min, m_max, m_median;
void sort( int v[], int n ) { /* Bubble sort */
for (int i=n-1; i > 0; --i)
for (int j=0; j < i; ++j)
if (v[j] > v[j+1]) {
int t = v[j];
v[j] = v[j+1];
v[j+1] = t;
}
cout << "Bubble: ";
for (int k=0; k < n; ++k)
cout << v[k] << ' ';
cout << '\n';
}
};
int main( void ) {
const int NUM = 9;
int array[NUM];
srand( time(0) );
cout << "Vector: ";
for (int i=0; i < NUM; ++i) {
array[i] = rand() % 9 + 1;
cout << array[i] << ' ';
}
cout << '\n';
Stat obj;
obj.readVector( array, NUM );
cout << "min is " << obj.getMin() << ", max is " << obj.getMax()
<< ", median is " << obj.getMedian() << '\n';
}
// Vector: 6 9 9 8 6 5 7 9 2
// Bubble: 2 5 6 6 7 8 9 9 9
// min is 2, max is 9, median is 7
// Strategy pattern - after (polymorphism)
//
// The notion of "sort" has been promoted to full object status.
// The Stat client is abstractly coupled to a Sort object of
// unknown implementation, and the end-user of Stat can affect
// the choice of implementation.
#include <iostream>
using std::cout;
class SortImpl {
public:
virtual void sort( int[], int ) = 0;
};
class SortBubble : public SortImpl {
public:
void sort( int v[], int n ) {
for (int i=n-1; i > 0; --i)
for (int j=0; j < i; ++j)
if (v[j] > v[j+1]) {
int t = v[j];
v[j] = v[j+1];
v[j+1] = t;
}
cout << "Bubble: ";
for (int k=0; k < n; k++)
cout << v[k] << ' ';
cout << '\n';
}
};
class SortShell : public SortImpl {
public:
void sort( int v[], int n ) {
for (int g = n/2; g > 0; g /= 2)
for (int i = g; i < n; ++i)
for (int j = i-g; j >= 0; j -= g)
if (v[j] > v[j+g]) {
int temp = v[j];
v[j] = v[j+g];
v[j+g] = temp;
}
cout << "Shell: ";
for (int k=0; k < n; k++)
cout << v[k] << ' ';
cout << '\n';
}
};
class Stat {
public:
Stat() { m_impl = new SortBubble; }
void upGrade() {
delete m_impl;
m_impl = new SortShell;
}
void downGrade() {
delete m_impl;
m_impl = new SortBubble;
}
void readVector( int v[], int n ) {
m_impl->sort( v, n );
m_min = v[0];
m_max = v[n-1];
m_median = v[n/2];
}
int getMin() { return m_min; }
int getMax() { return m_max; }
int getMedian() { return m_median; }
private:
int m_min, m_max, m_median;
SortImpl* m_impl;
};
int main( void ) {
const int NUM = 9;
int array1[NUM], array2[NUM];
srand( time(0) );
cout << "Vector: ";
for (int i=0; i < NUM; ++i) {
array1[i] = array2[i] = rand() % 9 + 1;
cout << array1[i] << ' '; }
cout << '\n';
Stat obj;
obj.upGrade();
obj.readVector( array1, NUM );
cout << "min is " << obj.getMin() << ", max is " << obj.getMax()
<< ", median is " << obj.getMedian() << '\n';
obj.downGrade();
obj.readVector( array2, NUM );
cout << "min is " << obj.getMin() << ", max is " << obj.getMax()
<< ", median is " << obj.getMedian() << '\n';
}
// Vector: 7 4 2 6 5 7 7 5 1
// Shell: 1 2 4 5 5 6 7 7 7
// min is 1, max is 7, median is 5
// Bubble: 1 2 4 5 5 6 7 7 7
// min is 1, max is 7, median is 5
// Strategy pattern - after (template approach)
//
// A template can be used to configure a client with a Strategy. This
// technique is appropriate if: 1) the Strategy can be selected at com-
// pile-time, and 2) it does not have to be changed at run-time. With
// a template, there is no need to specify the interface in a SortImpl
// base class. The Stat class now has an instance of the sort object,
// instead of a ptr to the base class. The inheritance approach offers
// more options and expressiveness. The template approach offers mildly
// better efficiency.
template<typename STRATEGY>
class Stat {
public:
void readVector( int v[], int n ) {
m_impl.sort( v, n );
m_min = v[0];
m_max = v[n-1];
m_median = v[n/2];
}
int getMin() { return m_min; }
int getMax() { return m_max; }
int getMedian() { return m_median; }
private:
int m_min, m_max, m_median;
STRATEGY m_impl;
};
class SortBubble {
public:
void sort( int v[], int n ) {
for (int i=n-1; i > 0; --i)
for (int j=0; j < i; ++j)
if (v[j] > v[j+1]) {
int t = v[j];
v[j] = v[j+1];
v[j+1] = t;
}
cout << "Bubble: ";
for (int k=0; k < n; k++)
cout << v[k] << ' ';
cout << '\n';
}
};
class SortShell {
public:
void sort( int v[], int n ) {
for (int g = n/2; g > 0; g /= 2)
for (int i = g; i < n; ++i)
for (int j = i-g; j >= 0; j -= g)
if (v[j] > v[j+g]) {
int temp = v[j];
v[j] = v[j+g];
v[j+g] = temp;
}
cout << "Shell: ";
for (int k=0; k < n; k++)
cout << v[k] << ' ';
cout << '\n';
}
};
int main( void ) {
const int NUM = 9;
int array[NUM];
srand( time(0) );
cout << "Vector: ";
for (int i=0; i < NUM; ++i) {
array[i] = rand() % 9 + 1;
cout << array[i] << ' ';
}
cout << '\n';
Stat<SortBubble> one;
one.readVector( array, NUM );
cout << "min is " << one.getMin() << ", max is " << one.getMax()
<< ", median is " << one.getMedian() << '\n';
Stat<SortShell> two;
two.readVector( array, NUM );
cout << "min is " << two.getMin() << ", max is " << two.getMax()
<< ", median is " << two.getMedian() << '\n';
}
// Vector: 8 3 1 9 7 2 2 9 7
// Bubble: 1 2 2 3 7 7 8 9 9
// min is 1, max is 9, median is 7
// Shell: 1 2 2 3 7 7 8 9 9
// min is 1, max is 9, median is 7
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Purpose. Strategy design pattern demo
//
// Discussion. The Strategy pattern suggests: encapsulating an algorithm
// in a class hierarchy, having clients of that algorithm hold a pointer
// to the base class of that hierarchy, and delegating all requests for
// the algorithm to that "anonymous" contained object. In this example,
// the Strategy base class knows how to collect a paragraph of input and
// implement the skeleton of the "format" algorithm. It defers some
// details of each individual algorithm to the "justify" member which is
// supplied by each concrete derived class of Strategy. The TestBed class
// models an application class that would like to leverage the services of
// a run-time-specified derived "Strategy" object.
#include <iostream.h>
#include <fstream.h>
#include <string.h>
class Strategy;
class TestBed {
public:
enum StrategyType { Dummy, Left, Right, Center };
TestBed() { strategy_ = NULL; }
void setStrategy( int type, int width );
void doIt();
private:
Strategy* strategy_;
};
class Strategy {
public:
Strategy( int width ) : width_( width ) { }
void format() {
char line[80], word[30];
ifstream inFile( "quote.txt", ios::in );
line[0] = '\0';
inFile >> word;
strcat( line, word );
while (inFile >> word)
{
if (strlen(line) + strlen(word) + 1 > width_)
justify( line );
else
strcat( line, " " );
strcat( line, word );
}
justify( line );
}
protected:
int width_;
private:
virtual void justify( char* line ) = 0;
};
class LeftStrategy : public Strategy {
public:
LeftStrategy( int width ) : Strategy( width ) { }
private:
/* virtual */ void justify( char* line ) {
cout << line << endl;
line[0] = '\0'; }
};
class RightStrategy : public Strategy {
public:
RightStrategy( int width ) : Strategy( width ) { }
private:
/* virtual */ void justify( char* line ) {
char buf[80];
int offset = width_ - strlen( line );
memset( buf, ' ', 80 );
strcpy( &(buf[offset]), line );
cout << buf << endl;
line[0] = '\0'; }
};
class CenterStrategy : public Strategy {
public:
CenterStrategy( int width ) : Strategy( width ) { }
private:
/* virtual */ void justify( char* line ) {
char buf[80];
int offset = (width_ - strlen( line )) / 2;
memset( buf, ' ', 80 );
strcpy( &(buf[offset]), line );
cout << buf << endl;
line[0] = '\0'; }
};
void TestBed::setStrategy( int type, int width ) {
delete strategy_;
if (type == Left) strategy_ = new LeftStrategy( width );
else if (type == Right) strategy_ = new RightStrategy( width );
else if (type == Center) strategy_ = new CenterStrategy( width ); }
void TestBed::doIt() { strategy_->format(); }
void main() {
TestBed test;
int answer, width;
cout << "Exit(0) Left(1) Right(2) Center(3): ";
cin >> answer;
while (answer)
{
cout << "Width: ";
cin >> width;
test.setStrategy( answer, width );
test.doIt();
cout << "Exit(0) Left(1) Right(2) Center(3): ";
cin >> answer;
}
return 0;
}
// Exit(0) Left(1) Right(2) Center(3): 2
// Width: 75
// The important lesson we have learned is that development for reuse is
// complex. If making a good design is difficult, then making a good reusable
// design is even harder, and any amount of process description cannot
// substitute for the skill, imagination, and experience of a good designer. A
// process can only support the creative work, and ensure that things are done
// and recorded properly. [Karlsson et al, REBOOT]
// Exit(0) Left(1) Right(2) Center(3): 3
// Width: 75
// The important lesson we have learned is that development for reuse is
// complex. If making a good design is difficult, then making a good reusable
// design is even harder, and any amount of process description cannot
// substitute for the skill, imagination, and experience of a good designer. A
// process can only support the creative work, and ensure that things are done
// and recorded properly. [Karlsson et al, REBOOT]
// Purpose. Template Method // Discussion. On the left, we're
// starting with 2 sorts that are very
#include <iostream.h> // similar. If we could "customize" a
#include <stdlib.h> // single sort implementation, we could
#include <time.h> // enjoy reuse. "Template Method de-
// fines an algorithm in terms of ab-
class SortUp { ///// Shell sort ///// // stract operations that subclasses
public: // override to provide concrete beha-
void doIt( int v[], int n ) { // vior." Here, doIt() is the algo-
for (int g = n/2; g > 0; g /= 2) // rithm, and needSwap() is the ab-
for (int i = g; i < n; i++) // stract operation.
for (int j = i-g; j >= 0;
j -= g) class Sort { ////// Shell sort //////
if (v[j] > v[j+g]) public:
doSwap(v[j],v[j+g]); void doIt( int v[], int n ) {
} for (int g = n/2; g > 0; g /= 2)
private: for (int i = g; i < n; i++)
void doSwap(int& a,int& b) { for (int j = i-g; j >= 0;
int t = a; a = b; b = t; } j -= g)
}; if (needSwap(v[j],
v[j+g]))
class SortDown { doSwap(v[j],
public: v[j+g]);
void doIt( int v[], int n ) { }
for (int g = n/2; g > 0; g /= 2) private:
for (int i = g; i < n; i++) virtual int needSwap(int,int) = 0;
for (int j = i-g; j >= 0; void doSwap(int& a,int& b) {
j -= g) int t = a; a = b; b = t; }
if (v[j] < v[j+g]) };
doSwap(v[j],v[j+g]);
} class SortUp : public Sort {
private: int needSwap(int a, int b) {
void doSwap(int& a,int& b) { return (a > b); }
int t = a; a = b; b = t; } };
}; class SortDown : public Sort {
int needSwap(int a, int b) {
void main( void ) return (a < b); }
{ };
const int NUM = 10;
int array[NUM]; void main( void )
time_t t; {
srand((unsigned) time(&t)); const int NUM = 10;
for (int i=0; i < NUM; i++) { int array[NUM];
array[i] = rand() % 10 + 1; time_t t;
cout << array[i] << ' '; } srand((unsigned) time(&t));
cout << endl; for (int i=0; i < NUM; i++) {
array[i] = rand() % 10 + 1;
SortUp upObj; cout << array[i] << ' '; }
upObj.doIt( array, NUM ); cout << endl;
for (int u=0; u < NUM; u++)
cout << array[u] << ' '; SortUp upObj;
cout << endl; upObj.doIt( array, NUM );
for (int u=0; u < NUM; u++)
SortDown downObj; cout << array[u] << ' ';
downObj.doIt( array, NUM ); cout << endl;
for (int d=0; d < NUM; d++)
cout << array[d] << ' '; SortDown downObj;
cout << endl; downObj.doIt( array, NUM );
} for (int d=0; d < NUM; d++)
cout << array[d] << ' ';
// 3 10 5 5 5 4 2 1 5 9 cout << endl;
// 1 2 3 4 5 5 5 5 9 10 }
// 10 9 5 5 5 5 4 3 2 1
// 1 6 6 2 10 9 4 10 6 4
// 1 2 4 4 6 6 6 9 10 10
// 10 10 9 6 6 6 4 4 2 1
// Purpose. No reuse
#include <iostream>
using namespace std;
class One {
void a() { cout << "a "; }
void b() { cout << "b "; }
void c() { cout << "c "; }
void d() { cout << "d "; }
void e() { cout << "e "; }
public:
void execute() { a(); b(); c(); d(); e(); }
};
class Two {
void a() { cout << "a "; }
void _2() { cout << "2 "; }
void c() { cout << "c "; }
void _4() { cout << "4 "; }
void e() { cout << "e "; }
public:
void execute() { a(); _2(); c(); _4(); e(); }
};
void main( void ) {
One first;
first.execute();
cout << '\n';
Two second;
second.execute();
cout << '\n';
}
// a b c d e
// a 2 c 4 e
// Purpose. Template Method design pattern
// 1. Standardize the skeleton of an algorithm in a base class "template method"
// 2. Steps requiring peculiar implementations are "placeholders" in base class
// 3. Derived classes implement placeholder methods
#include <iostream>
using namespace std;
class Base {
void a() { cout << "a "; }
void c() { cout << "c "; }
void e() { cout << "e "; }
// 2. Steps requiring peculiar implementations are "placeholders" in base class
virtual void ph1() = 0;
virtual void ph2() = 0;
public:
// 1. Standardize the skeleton of an algorithm in a base class "template method"
void execute() { a(); ph1(); c(); ph2(); e(); }
};
class One : public Base {
// 3. Derived classes implement placeholder methods
/*virtual*/ void ph1() { cout << "b "; }
/*virtual*/ void ph2() { cout << "d "; }
};
class Two : public Base {
/*virtual*/ void ph1() { cout << "2 "; }
/*virtual*/ void ph2() { cout << "4 "; }
};
void main( void ) {
Base* array[] = { &One(), &Two() };
for (int i=0; i < 2; i++) {
array[i]->execute();
cout << '\n';
} }
// a b c d e
// a 2 c 4 e
// Purpose. Template Method design pattern
// 1. Standardize the skeleton of an algorithm in a base class "template method"
// 2. Steps requiring peculiar implementations are "placeholders" in base class
// 3. Derived classes implement placeholder methods
#include <iostream>
#include <string>
using namespace std;
class StandardAlgorithm {
// 3. Steps requiring peculiar implementations are "placeholders" in base class
virtual string preprocess( char* ) = 0;
virtual bool validate( char ) = 0;
public:
// 1. Standardize the skeleton of algorithm in base class "template method"
string process( char* in ) {
string str = preprocess( in );
for (int i=0; i < str.size(); i++)
if ( ! validate( str[i] )) return "not valid";
return str;
} };
class Alphabetic : public StandardAlgorithm {
/*virtual*/ string preprocess( char* in ) {
string s( in );
for (int i=0; i < s.size(); i++)
if (s[i] >= 'A' && s[i] <= 'Z' || s[i] == ' ') /* empty */ ;
else if (s[i] >= 'a' && s[i] <= 'z') s[i] = s[i] - 32;
else s[i] = '_';
return s;
}
/*virtual*/ bool validate( char ch ) {
if (ch >= 'A' && ch <= 'Z' || ch == ' ') return true;
else return false;
} };
class Numeric : public StandardAlgorithm {
/*virtual*/ string preprocess( char* in ) { return in; }
/*virtual*/ bool validate( char ch ) {
if (ch >= '0' && ch <= '9') return true;
else return false;
} };
void main( void ) {
StandardAlgorithm* types[] = { &Alphabetic(), &Numeric() };
char buf[20];
while (true) {
cout << "Input: ";
cin.getline( buf, 20 );
if ( ! strcmp( buf, "quit" )) break;
for (int i=0; i < 2; i++)
cout << " " << types[i]->process( buf ) << '\n';
} }
// Input: Hello World
// HELLO WORLD
// not valid
// Input: 12345
// not valid
// 12345
// Input: 4.2e3
// not valid
// not valid
// Input: quit
// Purpose. Template Method design pattern
// 1. Standardize the skeleton of an algorithm in a base class "template" method
// 2. Common implementations of individual steps are defined in the base class
// 3. Steps requiring peculiar implementations are "placeholders" in base class
// 4. Derived classes can override placeholder methods
// 5. Derived classes can override implemented methods
// 6. Derived classes can override and "call back to" base class methods
#include <iostream>
using namespace std;
class A {
public:
// 1. Standardize the skeleton of an algorithm in a "template" method
void findSolution() {
stepOne();
stepTwo();
stepThr();
stepFor();
}
protected:
virtual void stepFor() { cout << "A.stepFor" << '\n'; }
private:
// 2. Common implementations of individual steps are defined in base class
void stepOne() { cout << "A.stepOne" << '\n'; }
// 3. Steps requiring peculiar impls are "placeholders" in the base class
virtual void stepTwo() = 0;
virtual void stepThr() = 0;
};
class B : public A {
// 4. Derived classes can override placeholder methods
// 1. Standardize the skeleton of an algorithm in a "template" method
/*virtual*/ void stepThr() {
step3_1();
step3_2();
step3_3();
}
// 2. Common implementations of individual steps are defined in base class
void step3_1() { cout << "B.step3_1" << '\n'; }
// 3. Steps requiring peculiar impls are "placeholders" in the base class
virtual void step3_2() = 0;
void step3_3() { cout << "B.step3_3" << '\n'; }
};
class C : public B {
// 4. Derived classes can override placeholder methods
/*virtual*/ void stepTwo() { cout << "C.stepTwo" << '\n'; }
void step3_2() { cout << "C.step3_2" << '\n'; }
// 5. Derived classes can override implemented methods
// 6. Derived classes can override and "call back to" base class methods
/*virtual*/ void stepFor() {
cout << "C.stepFor" << '\n';
A::stepFor();
} };
void main( void ) {
C algorithm;
algorithm.findSolution();
}
// A.stepOne
// C.stepTwo
// B.step3_1
// C.step3_2
// B.step3_3
// C.stepFor
// A.stepFor
// Purpose. Template Method design pattern demo.
//
// Discussion. The "template method" establishes the steps to be
// performed. All standard, or invariant, steps have their implementation
// provided by the abstract base class. All variable steps are not
// defined in the base class, but must be defined by concrete derived
// classes. "stepFour" below is an embellishment on the design pattern
// where the base class provides a default implementation, and then the
// derived class may extend that method by: overriding the method,
// "calling-back" to the base class to leverage its implementation, and
// then adding its own peculiar behavior.
#include <iostream.h>
class IncompleteAlgorithm {
public:
void doIt() { // this is the Template Method
stepOne(); // invariant, standard
stepTwo(); // invariant, standard
stepThree(); // variable, supplied by subclass
stepFour(); } // variable, default provided
private:
void stepOne() {
cout << "IncompleteAlgorithm::stepOne" << endl; }
void stepTwo() {
cout << "IncompleteAlgorithm::stepTwo" << endl; }
virtual void stepThree() = 0;
protected:
virtual void stepFour() {
cout << "IncompleteAlgorithm::stepFour" << endl; }
};
class FillInTheTemplate : public IncompleteAlgorithm {
/* virtual */ void stepThree() {
cout << "FillInTheTemplate::stepThree" << endl; }
/* virtual */ void stepFour() {
IncompleteAlgorithm::stepFour();
cout << "FillInTheTemplate::stepFour" << endl; }
};
void main() {
FillInTheTemplate theThingToDo;
theThingToDo.doIt();
}
// IncompleteAlgorithm::stepOne
// IncompleteAlgorithm::stepTwo
// FillInTheTemplate::stepThree
// IncompleteAlgorithm::stepFour
// FillInTheTemplate::stepFour
// Purpose. Template Method design pattern demo
//
// romanNumeral ::= {thousands} {hundreds} {tens} {ones}
// thousands, hundreds, tens, ones ::= nine | four | {five} {one} {one} {one}
// nine ::= "CM" | "XC" | "IX"
// four ::= "CD" | "XL" | "IV"
// five ::= 'D' | 'L' | 'V'
// one ::= 'M' | 'C' | 'X' | 'I'
#include <iostream>
#include <string>
using namespace std;
class Thousand; class Hundred; class Ten; class One;
class RNInterpreter {
public:
static int interpret( string input );
void interpret( string& input, int& total ) { // Template Method
int index = 0;
if (input.substr(0,2) == nine()) {
total += 9 * multiplier();
index += 2;
} else if (input.substr(0,2) == four()) {
total += 4 * multiplier();
index += 2;
} else {
if (input[0] == five()) {
total += 5 * multiplier();
index = 1;
}
for (int end = index + 3 ; index < end; index++)
if (input[index] == one())
total += 1 * multiplier();
else break;
}
// remove all leading chars processed
input.replace( 0, index, "" );
}
private:
virtual char one() = 0; virtual string four() = 0; // placeholders
virtual char five() = 0; virtual string nine() = 0; // placeholders
virtual int multiplier() = 0; // placeholders
static Thousand thousands; static Hundred hundreds;
static Ten tens; static One ones;
};
class Thousand : public RNInterpreter {
char one() { return 'M'; } string four() { return ""; }
char five() { return '\0'; } string nine() { return ""; }
int multiplier() { return 1000; }
};
class Hundred : public RNInterpreter {
char one() { return 'C'; } string four() { return "CD"; }
char five() { return 'D'; } string nine() { return "CM"; }
int multiplier() { return 100; }
};
class Ten : public RNInterpreter {
char one() { return 'X'; } string four() { return "XL"; }
char five() { return 'L'; } string nine() { return "XC"; }
int multiplier() { return 10; }
};
class One : public RNInterpreter {
char one() { return 'I'; } string four() { return "IV"; }
char five() { return 'V'; } string nine() { return "IX"; }
int multiplier() { return 1; }
};
Thousand RNInterpreter::thousands;
Hundred RNInterpreter::hundreds;
Ten RNInterpreter::tens;
One RNInterpreter::ones;
/*static*/ int RNInterpreter::interpret( string input ) {
int total = 0;
thousands.interpret( input, total );
hundreds.interpret( input, total );
tens.interpret( input, total );
ones.interpret( input, total );
// if any input remains, the input was invalid, return 0
if (input != "") return 0;
return total;
}
void main( void ) {
string input;
cout << "Enter Roman Numeral: ";
while (cin >> input) {
cout << " interpretation is " << RNInterpreter::interpret( input ) << endl;
cout << "Enter Roman Numeral: ";
} }
// Enter Roman Numeral: MCMXCVI
// interpretation is 1996
// Enter Roman Numeral: MMMCMXCIX
// interpretation is 3999
// Enter Roman Numeral: MMMM
// interpretation is 0
// Enter Roman Numeral: MDCLXVIIII
// interpretation is 0
// Enter Roman Numeral: CXCX
// interpretation is 0
// Enter Roman Numeral: MDCLXVI
// interpretation is 1666
// Enter Roman Numeral: DCCCLXXXVIII
// interpretation is 888
// Purpose. Visitor (adding ops) #include <iostream.h>
// class Visitor;
// Discussion. On the left, adding
// new operations requires modifying class Color { public:
// all the current Color classes. If virtual void accept( Visitor& ) = 0;
// we introduce an extra level of in- };
// direction (a Visitor hierarchy),
// then operations capable of opera- class Red : public Color { public:
// ting on Color classes can be added void accept( Visitor& );
// without modifying any existing void eye() { cout << "Red::eye\n"; }
// code. On the right, an entry point };
// for all future operations has been class Blu : public Color { public:
// added in the form of the accept() void accept( Visitor& );
// method. Each of the previous op- void sky() { cout << "Blu::sky\n"; }
// erations has been encapsulated in };
// its own derived Visitor class. Any
// new operations simply require the class Visitor { public:
// addition of a new Visitor class. virtual void visit( Red& ) = 0;
// virtual void visit( Blu& ) = 0;
// When we call accept() on a Color };
// object, dynamic binding gets us to
// the correct derived class of Color. class CountV : public Visitor {
// Then when we call visit() on the public:
// Visitor object, dynamic binding CountV() { numRed_ = numBlu_ = 0; }
// gets us to the correct derived virtual void visit( Red& ) {
// class of Visitor. [Visitors and numRed_++; }
// Colors can be passed by address or virtual void visit( Blu& ) {
// passed by reference.] numBlu_++; }
void reportNum() {
#include <iostream.h> cout << "Reds " << numRed_ <<
", Blus " << numBlu_ << endl; }
class Color { private:
public: int numRed_, numBlu_;
virtual void count() = 0; };
virtual void call() = 0;
static void reportNum() { class CallV : public Visitor { public:
cout << "Reds " << numRed_ << virtual void visit( Red& r ) {
", Blus " << numBlu_ <<endl; } r.eye(); }
protected: virtual void visit( Blu& b ) {
static int numRed_, numBlu_; b.sky(); }
}; };
int Color::numRed_ = 0;
int Color::numBlu_ = 0; void Red::accept( Visitor& v ) {
v.visit( *this ); }
class Red : public Color { public: void Blu::accept( Visitor& v ) {
void count() { numRed_++; } v.visit( *this ); }
void call() { eye(); }
void eye() { cout << "Red::eye\n";} void main( void )
}; {
Color* set[] = { new Red, new Blu,
class Blu : public Color { public: new Blu, new Red, new Red, 0 };
void count() { numBlu_++; } CountV countOp;
void call() { sky(); } CallV callOp;
void sky() { cout << "Blu::sky\n";} for (int i=0; set[i]; i++) {
}; set[i]->accept( countOp );
set[i]->accept( callOp ); }
void main( void ) countOp.reportNum();
{ }
Color* set[] = { new Red, new Blu,
new Blu, new Red, new Red, 0 }; // Red::eye
for (int i=0; set[i]; i++) { // Blu::sky
set[i]->count(); // Blu::sky
set[i]->call(); } // Red::eye
Color::reportNum(); // Red::eye
} // Reds 3, Blus 2
// Purpose. Visitor (double dispatch)
//
// Discussion. On the left, the State derived classes must query the type of
// the Cmd objects they receive, in order to identify what the next course of
// action is. "case" stmts are always a maintenance headache. On the right,
// we have recognized that what we really want to do is "dispatch" based on
// the type of TWO objects, (a State object and a Cmd object). The call to
// accept() discriminates the type of the State object that is being messaged,
// and then the call to visit() discriminates the type of the Cmd object
// (while passing the type of the State object). If new Cmd classes are
// added, no change whatsoever is necessary in the code of the State classes.
// If new State classes are added, then every Cmd class must be changed, and
// Visitor is NOT the right approach to take.
#include <iostream.h> #include <iostream.h>
int current = 0; int current = 0;
enum CmdTyp { OnT, OffT }; class One; class Two;
class Cmd { public: class Cmd { public:
virtual CmdTyp typ() = 0; virtual void visit( One* ) {
}; cout << "ERROR\n"; }
class On : public Cmd { public: virtual void visit( Two* ) {
CmdTyp typ() { return OnT; } cout << "ERROR\n"; }
}; };
class Off : public Cmd { public: class On : public Cmd { public:
CmdTyp typ() { return OffT; } void visit( One* ) {
}; current = 1;
cout << "One,On => Two\n"; }
class State { public: void visit( Two* t ) {
virtual void process( Cmd* c ) { Cmd::visit( t ); }
cout << "ERROR\n"; } };
}; class Off : public Cmd { public:
class One : public State { public: void visit( One* o ) {
void process( Cmd* c ) { Cmd::visit( o ); }
if (c->typ() == OnT) { void visit( Two* ) {
current = 1; current = 0;
cout << "One,On => Two\n"; } cout << "Two,Off => One\n"; }
else if (c->typ() == OffT) };
State::process( c );
} class State { public:
}; virtual void accept( Cmd* c ) = 0;
class Two : public State { public: };
void process( Cmd* c ) { class One : public State { public:
if (c->typ() == OnT) void accept( Cmd* c ) {
State::process( c ); c->visit( this ); }
else if (c->typ() == OffT) { };
current = 0; class Two : public State { public:
cout << "Two,Off => One\n"; } void accept( Cmd* c ) {
} c->visit( this ); }
}; };
State* states[] = { new One, new Two }; State* states[] = { new One, new Two };
void main( void ) void main( void )
{ {
Cmd* c[] = { new Off, Cmd* c[] = { new Off,
new On, new Off, new Off, 0 }; new On, new Off, new Off, 0 };
for (int i=0; c[i]; i++) for (int i=0; c[i]; i++)
states[current]->process( c[i] ); states[current]->accept( c[i] );
} }
// ERROR // ERROR
// One,On => Two // One,On => Two
// Two,Off => One // Two,Off => One
// ERROR // ERROR
// Purpose. Visitor design pattern
// 1. Add an accept(Visitor) method to the "element" hierarchy
// 2. Create a "visitor" base class w/ a visit() method for every "element" type
// 3. Create a "visitor" derived class for each "operation" to do on "elements"
// 4. Client creates "visitor" objects and passes each to accept() calls
#include <iostream>
#include <string>
using namespace std;
// 1. Add an accept(Visitor) method to the "element" hierarchy
class Element { public:
virtual void accept( class Visitor& v ) = 0;
};
class This : public Element { public:
/*virtual*/ void accept( Visitor& v );
string thiss() { return "This"; }
};
class That : public Element { public:
/*virtual*/ void accept( Visitor& v );
string that() { return "That"; }
};
class TheOther : public Element { public:
/*virtual*/ void accept( Visitor& v );
string theOther() { return "TheOther"; }
};
// 2. Create a "visitor" base class w/ a visit() method for every "element" type
class Visitor { public:
virtual void visit( This* e ) = 0;
virtual void visit( That* e ) = 0;
virtual void visit( TheOther* e ) = 0;
};
/*virtual*/ void This::accept( Visitor& v ) { v.visit( this ); }
/*virtual*/ void That::accept( Visitor& v ) { v.visit( this ); }
/*virtual*/ void TheOther::accept( Visitor& v ) { v.visit( this ); }
// 3. Create a "visitor" derived class for each "operation" to do on "elements"
class UpVisitor : public Visitor {
/*virtual*/ void visit( This* e ) {
cout << "do Up on " + e->thiss() << '\n'; }
/*virtual*/ void visit( That* e ) {
cout << "do Up on " + e->that() << '\n'; }
/*virtual*/ void visit( TheOther* e ) {
cout << "do Up on " + e->theOther() << '\n'; }
};
class DownVisitor : public Visitor {
/*virtual*/ void visit( This* e ) {
cout << "do Down on " + e->thiss() << '\n'; }
/*virtual*/ void visit( That* e ) {
cout << "do Down on " + e->that() << '\n'; }
/*virtual*/ void visit( TheOther* e ) {
cout << "do Down on " + e->theOther() << '\n'; }
};
void main( void ) {
Element* list[] = { new This(), new That(), new TheOther() };
UpVisitor up; // 4. Client creates
DownVisitor down; // "visitor" objects
for (int i=0; i < 3; i++) // and passes each
list[i]->accept( up ); // to accept() calls
for (i=0; i < 3; i++)
list[i]->accept( down );
}
// do Up on This // do Down on This
// do Up on That // do Down on That
// do Up on TheOther // do Down on TheOther
// Purpose. Visitor - recovering lost type information
//
// Motivation. "My Component classes do not know that Composites exist.
// They provide no help for navigating Composites, nor any help for
// altering the contents of a Composite. This is because I would like the
// base class (and all its derivatives) to be reusable in contexts that do
// not require Composites. When given a base class pointer, if I
// absolutely need to know whether or not it is a Composite, I will use
// dynamic_cast() to figure this out. In those cases where dynamic_cast()
// is too expensive, I will use a Visitor." [Robert Martin]
#include <iostream>
#include <vector>
using namespace std;
class Visitor { public:
virtual void visit( class Primitive*, class Component* ) = 0;
virtual void visit( class Composite*, Component* ) = 0;
};
class Component {
int value;
public:
Component( int val ) { value = val; }
virtual void traverse() { cout << value << " "; }
// Having add() here sacrifices safety, but it supports transparency
// virtual void add( Component* ) { }
virtual void accept( Visitor&, Component* ) = 0;
};
class Primitive : public Component { public:
Primitive( int val ) : Component( val ) { }
/*virtual*/ void accept( Visitor& v, Component* c ) { v.visit( this, c ); }
};
class Composite : public Component {
vector<Component*> children;
public:
Composite( int val ) : Component( val ) { }
void add( Component* ele ) { children.push_back( ele ); }
/*virtual*/ void accept( Visitor& v, Component* c ) { v.visit( this, c ); }
/*virtual*/ void traverse() {
Component::traverse();
for (int i=0; i < children.size(); i++)
children[i]->traverse();
} };
class AddVisitor : public Visitor { public:
/*virtual*/ void visit( Primitive*, Component* ) {/* does not make sense */}
/*virtual*/ void visit( Composite* node, Component* c ) { node->add( c ); }
};
void main( void ) {
Component* nodes[3];
// The type of Composite* is "lost" when the object is assigned to a
// Component*
nodes[0] = new Composite(1);
nodes[1] = new Composite(2);
nodes[2] = new Composite(3);
// If add() were in class Component, this would work
// nodes[0]->add( nodes[1] );
// If it is NOT in Component, and only in Composite, you get the error -
// no member function `Component::add(Component *)' defined
// Instead of sacrificing safety, we use a Visitor to support add()
AddVisitor addVisitor;
nodes[0]->accept( addVisitor, nodes[1] );
nodes[0]->accept( addVisitor, nodes[2] );
nodes[0]->accept( addVisitor, new Primitive(4) );
nodes[1]->accept( addVisitor, new Primitive(5) );
nodes[1]->accept( addVisitor, new Primitive(6) );
nodes[2]->accept( addVisitor, new Primitive(7) );
for (int i=0; i < 3; i++) {
nodes[i]->traverse();
cout << endl;
} }
// 1 2 5 6 3 7 4
// 2 5 6
// 3 7
// Purpose. Combining Visitor with Composite's recursive traversal
#include <iostream>
#include <vector>
using namespace std;
class Visitor { public:
virtual void visit( class Leaf* e ) = 0;
virtual void visit( class Composite* e ) = 0;
};
class Component { public:
virtual void traverse() = 0;
virtual void accept( class Visitor& v ) = 0;
};
class Leaf : public Component {
int value;
public:
Leaf( int val ) { value = val; }
/*virtual*/ void traverse() { cout << value << ' '; }
/*virtual*/ void accept( class Visitor& v ) { v.visit( this ); }
int getValue() { return value; }
};
class Composite : public Component {
char value;
vector<Component*> children;
static char next;
public:
Composite() { value = next++; }
void add( Component* ele ) { children.push_back( ele ); }
/*virtual*/ void traverse() {
cout << value << ' ';
for (int i=0; i < children.size(); i++)
children[i]->traverse();
}
/*virtual*/ void accept( class Visitor& v ) {
v.visit( this );
// accept() has been embellished to include the logic in traverse()
for (int i=0; i < children.size(); i++)
children[i]->accept( v );
}
char getValue() { return value; }
};
char Composite::next = 'a';
class TransformVisitor : public Visitor { public:
/*virtual*/ void visit( Leaf* e ) { cout << e->getValue() + 100 << ' '; }
/*virtual*/ void visit( Composite* e ) { cout << (char)(e->getValue()-32) <<' ';}
};
void main( void ) {
Composite containers[4];
for (int i=0; i < 4; i++)
for (int j=0; j < 3; j++)
containers[i].add( new Leaf( i * 3 + j ) );
for (i=1; i < 4; i++) containers[0].add( &(containers[i]) );
containers[0].traverse(); cout << endl;
TransformVisitor tv;
// don't need an "iteration" capability with this design
containers[0].accept( tv ); cout << endl;
}
// a 0 1 2 b 3 4 5 c 6 7 8 d 9 10 11
// A 100 101 102 B 103 104 105 C 106 107 108 D 109 110 111
// Purpose. Undesireable design - double dispatch - doing the right thing based
// on the type of two objects
#include <iostream>
#include <string>
using namespace std;
class Request { public: virtual string getType() = 0; };
class R1 : public Request { public:
/*virtual*/ string getType() { return "One"; }
void reqOneMethod( class P1* );
void reqOneMethod( class P2* );
};
class R2 : public Request { public:
/*virtual*/ string getType() { return "Two"; }
void reqTwoMethod( P1* );
void reqTwoMethod( P2* );
};
class Processor { public: virtual void handle( class Request* ) = 0; };
class P1 : public Processor { public:
/*virtual*/ void handle( class Request* req ) {
if (req->getType() == string("One")) ((R1*)req)->reqOneMethod( this );
else if (req->getType() == string("Two")) ((R2*)req)->reqTwoMethod( this );
}
void procOneMethod() { cout << "processor one handling "; }
};
class P2 : public Processor { public:
/*virtual*/ void handle( class Request* req ) {
if (req->getType() == string("One")) ((R1*)req)->reqOneMethod( this );
else if (req->getType() == string("Two")) ((R2*)req)->reqTwoMethod( this );
}
void procTwoMethod() { cout << "processor two handling "; }
};
void R1::reqOneMethod( P1* p ) { p->procOneMethod(); cout << "request one\n"; }
void R1::reqOneMethod( P2* p ) { p->procTwoMethod(); cout << "request one\n"; }
void R2::reqTwoMethod( P1* p ) { p->procOneMethod(); cout << "request two\n"; }
void R2::reqTwoMethod( P2* p ) { p->procTwoMethod(); cout << "request two\n"; }
void main( void ) {
Processor* handlers[] = { new P1(), new P2() };
Request* commands[] = { new R1(), new R2() };
for (int i=0; i < 2; i++)
for (int j=0; j < 2; j++)
handlers[i]->handle( commands[j] );
}
// processor one handling request one
// processor one handling request two
// processor two handling request one
// processor two handling request two
// Purpose. Visitor - double dispatch - doing the right thing based on the
// type of two objects
#include <iostream>
#include <string>
using namespace std;
class Request { public:
// second dispatch - the "visit()" method
virtual void execute( class P1* ) = 0;
virtual void execute( class P2* ) = 0;
};
class R1 : public Request { public:
/*virtual*/ void execute( P1* );
/*virtual*/ void execute( P2* );
};
class R2 : public Request { public:
/*virtual*/ void execute( P1* );
/*virtual*/ void execute( P2* );
};
class Processor { public:
// first dispatch - the "accept()" method
virtual void handle( class Request* ) = 0;
};
class P1 : public Processor { public:
/*virtual*/ void handle( Request* req ) { req->execute( this ); }
void procOneMethod() { cout << "processor one handling "; }
};
class P2 : public Processor { public:
/*virtual*/ void handle( Request* req ) { req->execute( this ); }
void procTwoMethod() { cout << "processor two handling "; }
};
/*virtual*/ void R1::execute( P1* p ) { p->procOneMethod(); cout << "request one\n"; }
/*virtual*/ void R1::execute( P2* p ) { p->procTwoMethod(); cout << "request one\n"; }
/*virtual*/ void R2::execute( P1* p ) { p->procOneMethod(); cout << "request two\n"; }
/*virtual*/ void R2::execute( P2* p ) { p->procTwoMethod(); cout << "request two\n"; }
void main( void ) {
Processor* handlers[] = { new P1(), new P2() };
Request* commands[] = { new R1(), new R2() };
for (int i=0; i < 2; i++)
for (int j=0; j < 2; j++)
handlers[i]->handle( commands[j] );
}
// processor one handling request one
// processor one handling request two
// processor two handling request one
// processor two handling request two
// Purpose. Acyclic Visitor design pattern [PLOPD vol 3, p93]
//
// Problem. In GOF Visitor, Element depends on Visitor, Visitor depends on
// all Element derivatives, and Element derivatives depend on Element; this is
// cyclic dependency. Additionally, adding an Element derivative requires the
// entire Visitor hierarchy to change. "These problems can be solved by using
// multiple inheritance and dynamic_cast()."
//
// Solution. Element derived classes are only coupled to Visitor base class.
// Visitor derived classes are only coupled to the Element derived classes that
// they choose to be coupled to. If a new Element derived class is added,
// Visitor derived classes can update themselves if, and when, they choose.
#include <iostream>
#include <string>
using namespace std;
class Element { public:
virtual void accept( class Visitor& v ) = 0;
};
class This : public Element { public:
/*virtual*/ void accept( Visitor& v );
string thiss() { return "This"; }
};
class That : public Element { public:
/*virtual*/ void accept( Visitor& v );
string that() { return "That"; }
};
class TheOther : public Element { public:
/*virtual*/ void accept( Visitor& v );
string theOther() { return "TheOther"; }
};
class Visitor { public:
virtual ~Visitor() { };
};
class ThisVisitor { public:
virtual void visit( This* e ) = 0;
};
class ThatVisitor { public:
virtual void visit( That* e ) = 0;
};
class TheOtherVisitor { public:
virtual void visit( TheOther* e ) = 0;
};
/*virtual*/ void This::accept( Visitor& v ) {
ThisVisitor* tv = dynamic_cast<ThisVisitor*>( &v );
if (tv) tv->visit( this );
else cout << "the visitor was not accepted\n";
}
/*virtual*/ void That::accept( Visitor& v ) {
ThatVisitor* tv = dynamic_cast<ThatVisitor*>( &v );
if (tv) tv->visit( this );
else cout << "the visitor was not accepted\n";
}
/*virtual*/ void TheOther::accept( Visitor& v ) {
TheOtherVisitor* tv = dynamic_cast<TheOtherVisitor*>( &v );
if (tv) tv->visit( this );
else cout << "the visitor was not accepted\n";
}
class UpVisitor : public Visitor, public ThisVisitor, public ThatVisitor,
public TheOtherVisitor {
/*virtual*/ void visit( This* e ) {
cout << "do Up on " + e->thiss() << '\n'; }
/*virtual*/ void visit( That* e ) {
cout << "do Up on " + e->that() << '\n'; }
/*virtual*/ void visit( TheOther* e ) {
cout << "do Up on " + e->theOther() << '\n'; }
};
class DownVisitor : public Visitor, public ThisVisitor, public ThatVisitor,
public TheOtherVisitor {
/*virtual*/ void visit( This* e ) {
cout << "do Down on " + e->thiss() << '\n'; }
/*virtual*/ void visit( That* e ) {
cout << "do Down on " + e->that() << '\n'; }
/*virtual*/ void visit( TheOther* e ) {
cout << "do Down on " + e->theOther() << '\n'; }
};
void main( void ) {
Element* list[] = { new This(), new That(), new TheOther() };
UpVisitor up; // 4. Client creates
DownVisitor down; // "visitor" objects
for (int i=0; i < 3; i++) // and passes each
list[i]->accept( up ); // to accept() calls
for (i=0; i < 3; i++)
list[i]->accept( down );
}
// do Up on This // do Down on This
// do Up on That // do Down on That
// do Up on TheOther // do Down on TheOther
// Purpose. Double dispatch (within a single hierarchy)
//
// Discussion. We would like to declare a function like:
// void process( virtual Base* object1, virtual Base* object2 )
// that does the right thing based on the type of 2 objects that come from
// a single inheritance hierarchy. The only problem is that the keyword
// "virtual" may not be used to request dynamic binding for an object being
// passed as an argument. C++ will only "discriminate" the type of an object
// being messaged, not the type of an object being passed. So in order for
// the type of 2 objects to be discriminated, each object must be the
// receiver of a virtual function call. Here, when process1() is called on
// the first object, its type becomes "known" at runtime, but the type of
// the second is still UNknown. process2() is then called on the second
// object, and the identity (and type) of the first object is passed as an
// argument. Flow of control has now been vectored to the spot where the
// type (and identity) of both objects are known.
#include <iostream>
using namespace std;
class Base { public:
virtual void process1( Base& ) = 0;
virtual void process2( class A& ) = 0;
virtual void process2( class B& ) = 0;
virtual void process2( class C& ) = 0;
};
class A : public Base { public:
/*virtual*/ void process1( Base& second ) { second.process2( *this ); }
/*virtual*/ void process2( class A& first ) {
cout << "first is A, second is A\n"; }
/*virtual*/ void process2( class B& first ) {
cout << "first is B, second is A\n"; }
/*virtual*/ void process2( class C& first ) {
cout << "first is C, second is A\n"; }
};
class B : public Base { public:
/*virtual*/ void process1( Base& second ) { second.process2( *this ); }
/*virtual*/ void process2( class A& first ) {
cout << "first is A, second is B\n"; }
/*virtual*/ void process2( class B& first ) {
cout << "first is B, second is B\n"; }
/*virtual*/ void process2( class C& first ) {
cout << "first is C, second is B\n"; }
};
class C : public Base { public:
/*virtual*/ void process1( Base& second ) { second.process2( *this ); }
/*virtual*/ void process2( class A& first ) {
cout << "first is A, second is C\n"; }
/*virtual*/ void process2( class B& first ) {
cout << "first is B, second is C\n"; }
/*virtual*/ void process2( class C& first ) {
cout << "first is C, second is C\n"; }
};
void main( void ) {
Base* array[] = { &A(), &B(), &C() };
for (int i=0; i < 3; i++)
for (int j=0; j < 3; j++)
array[i]->process1( *array[j] );
}
// first is A, second is A
// first is A, second is B
// first is A, second is C
// first is B, second is A
// first is B, second is B
// first is B, second is C
// first is C, second is A
// first is C, second is B
// first is C, second is C
// Purpose. Triple dispatch (within a single hierarchy)
//
// Discussion. It would be nice if C++ supported creating a function like:
// "processCombine( virtual Binary& first, virtual Binary& second, virtual
// Binary& third )". While not directly supported, we can simulate this kind
// of capability by: calling combine() on the first object to resolve its
// type, then calling combine() on the second object to resolve its type,
// then calling combine() on the third object to resolve its type. We
// "remember" the type information we have "discriminated" at each stage by
// juggling the three objects through 2 increasingly type-specific parameter
// slots.
#include <iostream>
using namespace std;
class Zero;
class One;
class Binary {
public:
// First dispatch
virtual void combine( Binary& second, Binary& third ) = 0;
// Second dispatch
virtual void combine( Binary& third, Zero& first ) = 0;
virtual void combine( Binary& third, One& first ) = 0;
// Third dispatch
virtual void combine( Zero& first, Zero& second ) = 0;
virtual void combine( Zero& first, One& second ) = 0;
virtual void combine( One& first, Zero& second ) = 0;
virtual void combine( One& first, One& second ) = 0;
};
class Zero : public Binary {
public:
void combine( Binary& second, Binary& third ) {
second.combine( third, *this ); }
void combine( Binary& third, Zero& first ) {
third.combine( first, *this ); }
void combine( Binary& third, One& first ) {
third.combine( first, *this ); }
void combine( Zero& first, Zero& second );
void combine( Zero& first, One& second );
void combine( One& first, Zero& second );
void combine( One& first, One& second );
void doZero() { cout << "0 "; }
};
class One : public Binary {
public:
void combine( Binary& second, Binary& third ) {
second.combine( third, *this ); }
void combine( Binary& third, Zero& first ) {
third.combine( first, *this ); }
void combine( Binary& third, One& first ) {
third.combine( first, *this ); }
void combine( Zero& first, Zero& second );
void combine( Zero& first, One& second );
void combine( One& first, Zero& second );
void combine( One& first, One& second );
void doOne() { cout << "1 "; }
};
void Zero::combine( Zero& first, Zero& second ) {
first.doZero(); second.doZero(); doZero(); cout << endl; }
void Zero::combine( Zero& first, One& second ) {
first.doZero(); second.doOne(); doZero(); cout << endl; }
void Zero::combine( One& first, Zero& second ) {
first.doOne(); second.doZero(); doZero(); cout << endl; }
void Zero::combine( One& first, One& second ) {
first.doOne(); second.doOne(); doZero(); cout << endl; }
void One::combine( Zero& first, Zero& second ) {
first.doZero(); second.doZero(); doOne(); cout << endl; }
void One::combine( Zero& first, One& second ) {
first.doZero(); second.doOne(); doOne(); cout << endl; }
void One::combine( One& first, Zero& second ) {
first.doOne(); second.doZero(); doOne(); cout << endl; }
void One::combine( One& first, One& second ) {
first.doOne(); second.doOne(); doOne(); cout << endl; }
void processCombine( Binary& first, Binary& second, Binary& third ) {
first.combine( second, third );
}
void main( void ) {
Binary* list[2] = { &Zero(), &One() };
// Run through permutations
for (int i=0; i < 2; i++)
for (int j=0; j < 2; j++)
for (int k=0; k < 2; k++)
processCombine( *list[i], *list[j], *list[k] );
}
// 0 0 0
// 0 0 1
// 0 1 0
// 0 1 1
// 1 0 0
// 1 0 1
// 1 1 0
// 1 1 1