100% found this document useful (10 votes)
121 views84 pages

Data Structures Algorithms and Applications in C++ With Microsoft Compiler 1st Edition by Sartaj Sahni ISBN 007236226X 978-0072362268

The document provides information about various textbooks on data structures and algorithms, specifically in C and C++. It includes links to download the full versions of these textbooks, along with their ISBNs and authors. Additionally, it mentions the copyright and publishing details for the textbooks, emphasizing that they are intended for educational purposes.

Uploaded by

skudaiphany
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (10 votes)
121 views84 pages

Data Structures Algorithms and Applications in C++ With Microsoft Compiler 1st Edition by Sartaj Sahni ISBN 007236226X 978-0072362268

The document provides information about various textbooks on data structures and algorithms, specifically in C and C++. It includes links to download the full versions of these textbooks, along with their ISBNs and authors. Additionally, it mentions the copyright and publishing details for the textbooks, emphasizing that they are intended for educational purposes.

Uploaded by

skudaiphany
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 84

Visit ebookball.

com to download the full version and


explore more ebook or textbook

Data Structures Algorithms and Applications in C++


With Microsoft Compiler 1st edition by Sartaj
Sahni ISBN 007236226X 978-0072362268

_____ Click the link below to download _____


https://ebookball.com/product/data-structures-algorithms-
and-applications-in-c-with-microsoft-compiler-1st-edition-
by-sartaj-sahni-isbn-007236226x-978-0072362268-16394/

Explore and download more ebook or textbook at ebookball.com


Here are some recommended products that we believe you will be
interested in. You can click the link to download.

Data Structures Algorithms and Applications in C With


Microsoft Compiler 2nd Edition by Sartaj Sahni ISBN
0929306325 9780929306322
https://ebookball.com/product/data-structures-algorithms-and-
applications-in-c-with-microsoft-compiler-2nd-edition-by-sartaj-sahni-
isbn-0929306325-9780929306322-15764/

Data Structures Algorithms and Applications in C++ With


Microsoft Compiler 2nd edition by Michael Goodrich,
Roberto Tamassia, David Mount ISBN B005FHM6X2
978-0470383278
https://ebookball.com/product/data-structures-algorithms-and-
applications-in-c-with-microsoft-compiler-2nd-edition-by-michael-
goodrich-roberto-tamassia-david-mount-
isbn-b005fhm6x2-978-0470383278-16544/

Handbook of data structures and applications 1st edition


by Dinesh Mehta, Sartaj Sahni 1498701884 9781498701884

https://ebookball.com/product/handbook-of-data-structures-and-
applications-1st-edition-by-dinesh-mehta-sartaj-
sahni-1498701884-9781498701884-19980/

Fundamentals of Data Structures 1st Edition by Ellis


Horowitz, Sartaj Sahni ISBN

https://ebookball.com/product/fundamentals-of-data-structures-1st-
edition-by-ellis-horowitz-sartaj-sahni-isbn-12560/
Data Structures Algorithms and Applications in C++ 1st
edition by Adam Drozdek ISBN 1133608426 9781133608424

https://ebookball.com/product/data-structures-algorithms-and-
applications-in-c-1st-edition-by-adam-drozdek-
isbn-1133608426-9781133608424-17250/

Data Structures and Algorithms in C 1st edition by Adam


Drozdek ASIN B002WLXMBY

https://ebookball.com/product/data-structures-and-algorithms-in-c-1st-
edition-by-adam-drozdek-asin-b002wlxmby-25076/

Computer Science and Compiler Design An Introduction with


C 1st Edition by Compiler Generators in C ISBN

https://ebookball.com/product/computer-science-and-compiler-design-an-
introduction-with-c-1st-edition-by-compiler-generators-in-c-
isbn-11720/

Problem Solving in Data Structures and Algorithms Using C


1st Edition by Hemant Jain ISBN 9352655915 9789352655915

https://ebookball.com/product/problem-solving-in-data-structures-and-
algorithms-using-c-1st-edition-by-hemant-jain-
isbn-9352655915-9789352655915-15768/

Problem Solving in Data Structures and Algorithms Using C


1st Edition by Hemant Jain ISBN 1540407306 9781540407306

https://ebookball.com/product/problem-solving-in-data-structures-and-
algorithms-using-c-1st-edition-by-hemant-jain-
isbn-1540407306-9781540407306-15866/
Data Structures
and Algorithms
in C++

Fourth Edition

Adam Drozdek

Australia • Brazil • Japan • Korea • Mexico • Singapore • Spain • United Kingdom • United States

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
This is an electronic version of the print textbook. Due to electronic rights restrictions,
some third party content may be suppressed. Editorial review has deemed that any suppressed
content does not materially affect the overall learning experience. The publisher reserves the right
to remove content from this title at any time if subsequent rights restrictions require it. For
valuable information on pricing, previous editions, changes to current editions, and alternate
formats, please visit www.cengage.com/highered to search by ISBN#, author, title, or keyword for
materials in your areas of interest.

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Data Structures and © 2013 Cengage Learning
Algorithms in C++,
ALL RIGHTS RESERVED. No part of this work covered by the copyright herein
Fourth Edition
may be reproduced, transmitted, stored or used in any form or by any means
by Adam Drozdek graphic, electronic, or mechanical, including but not limited to photocopying,
Executive Editor: Marie Lee recording, scanning, digitizing, taping, Web distribution, information networks,
or information storage and retrieval systems, except as permitted under
Senior Product Manager:
Section 107 or 108 of the 1976 United States Copyright Act, without the prior
Alyssa Pratt
written permission of the publisher.
Associate Product Manager:
Stephanie Lorenz
For product information and technology assistance, contact us at
Content Project Manager: Cengage Learning Customer & Sales Support, www.cengage.com/support
Matthew Hutchinson For permission to use material from this text or product, submit all
Art Director: Cheryl Pearl requests online at www.cengage.com/permissions
Further permissions questions can be emailed to
Print Buyer: Julio Esperas
[email protected]
Compositor: PreMediaGlobal
Proofreader: Andrea Schein Library of Congress Control Number: 2012942244
Indexer: Sharon Hilgenberg ISBN-13: 978-1-133-60842-4
ISBN-10: 1-133-60842-6
Cengage Learning
20 Channel Center Street
Boston, MA 02210
USA
Cengage Learning is a leading provider of customized learning solutions with
office locations around the globe, including Singapore, the United Kingdom,
Australia, Mexico, Brazil and Japan. Locate your local office at:
www.cengage.com/global
Cengage Learning products are represented in Canada by Nelson Education, Ltd.
To learn more about Cengage Learning, visit www.cengage.com
Purchase any of our products at your local college store or at our preferred
online store www.cengagebrain.com

Some of the product names and company names used in this book have been used for identification purposes only
and may be trademarks or registered trademarks of their respective manufacturers and sellers.

Any fictional data related to persons or companies or URLs used throughout this book is intended for instructional
purposes only. At the time this book was printed, any such data was fictional and not belonging to any real persons or
companies.

Cengage Learning reserves the right to revise this publication and make changes from time to time in its content
without notice.

The programs in this book are for instructional purposes only. They have been tested with care, but are not guaranteed
for any particular intent beyond educational purposes. The author and the publisher do not offer any warranties or repre-
sentations, nor do they accept any liabilities with respect to the programs.

Printed in the United States of America


1 2 3 4 5 6 7 18 17 16 15 14 13 12
Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
To my daughters, Justyna and Kasia

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Contents

1 Object-Oriented Programming Using C++ 1


1.1 Abstract Data Types 1
1.2 Encapsulation 1
1.3 Inheritance 6
1.4 Pointers 9
1.4.1 Pointers and Arrays 12
1.4.2 Pointers and Copy Constructors 14
1.4.3 Pointers and Destructors 16
1.4.4 Pointers and Reference Variables 17
1.4.5 Pointers to Functions 20
1.5 Polymorphism 21
1.6 C++ and Object-Oriented Programming 23
1.7 The Standard Template Library 24
1.7.1 Containers 24
1.7.2 Iterators 25
1.7.3 Algorithms 25
1.7.4 Function Objects 26
1.8 Vectors in the Standard Template Library 28
1.9 Data Structures and Object-Oriented Programming 35
1.10 Case Study: Random Access File 35
1.11 Exercises   46
1.12 Programming Assignments   48
Bibliography   50

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
vi ■ Contents

2 Complexity Analysis 51
2.1 Computational and Asymptotic Complexity 51
2.2 Big-O Notation 52
2.3 Properties of Big-O Notation 54
2.4 Ω and Θ Notations 56
2.5 Possible Problems 57
2.6 Examples of Complexities 57
2.7 Finding Asymptotic Complexity: Examples 59
2.8 The Best, Average, and Worst Cases 61
2.9 Amortized Complexity 64
2.10 NP-Completeness 68
2.11 Exercises   71
Bibliography   74

3 Linked Lists 75
3.1 Singly Linked Lists 75
3.1.1 Insertion 81
3.1.2 Deletion 83
3.1.3 Search 89
3.2 Doubly Linked Lists 90
3.3 Circular Lists 94
3.4 Skip Lists 96
3.5 Self-Organizing Lists 101
3.6 Sparse Tables 106
3.7 Lists in the Standard Template Library 109
3.8 Concluding Remarks 113
3.9 Case Study: A Library 114
3.10 Exercises   125
3.11 Programming Assignments   127
Bibliography   130

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Contents ■ vii

4 Stacks and Queues 131


4.1 Stacks 131
4.2 Queues 139
4.3 Priority Queues 148
4.4 Stacks in the Standard Template Library 149
4.5 Queues in the Standard Template Library 149
4.6 Priority Queues in the Standard Template Library 151
4.7 Deques in the Standard Template Library 153
4.8 Case Study: Exiting a Maze 158
4.9 Exercises   165
4.10 Programming Assignments   166
Bibliography   168

5 Recursion 169
5.1 Recursive Definitions 169
5.2 Function Calls and Recursion Implementation 172
5.3 Anatomy of a Recursive Call 174
5.4 Tail Recursion 177
5.5 Nontail Recursion 178
5.6 Indirect Recursion 184
5.7 Nested Recursion 186
5.8 Excessive Recursion 186
5.9 Backtracking 190
5.10 Concluding Remarks 197
5.11 Case Study: A Recursive Descent Interpreter 198
5.12 Exercises   207
5.13 Programming Assignments   210
Bibliography   213

6 Binary Trees 214


6.1 Trees, Binary Trees, and Binary Search Trees 214
6.2 Implementing Binary Trees 219
6.3 Searching a Binary Search Tree 222
Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
viii ■ Contents

6.4 Tree Traversal 224


6.4.1 Breadth-First Traversal 225
6.4.2 Depth-First Traversal 226
6.4.3 Stackless Depth-First Traversal 233
6.5 Insertion 240
6.6 Deletion 243
6.6.1 Deletion by Merging 244
6.6.2 Deletion by Copying 246
6.7 Balancing a Tree 250
6.7.1 The DSW Algorithm 253
6.7.2 AVL Trees 256
6.8 Self-Adjusting Trees 261
6.8.1 Self-Restructuring Trees 262
6.8.2 Splaying 263
6.9 Heaps 268
6.9.1 Heaps as Priority Queues 270
6.9.2 Organizing Arrays as Heaps 271
6.10 Treaps 276
6.11 k-d Trees 280
6.12 Polish Notation and Expression Trees 286
6.12.1 Operations on Expression Trees 287
6.13 Case Study: Computing Word Frequencies 290
6.14 Exercises   298
6.15 Programming Assignments   302
Bibliography   306

7 Multiway Trees 309


7.1 The Family of B-Trees 310
7.1.1 B-Trees 311
7.1.2 B*-Trees 321
7.1.3 B+-Trees 323
7.1.4 Prefix B+-Trees 326
7.1.5 K‑d B-trees 327
7.1.6 Bit-Trees 334
7.1.7 R-Trees 336
7.1.8 2–4 Trees 337
7.1.9 Sets and Multisets in the Standard Template Library 353
7.1.10 Maps and Multimaps in the Standard Template Library 359

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Contents ■ ix

7.2 Tries 364


7.3 Concluding Remarks 373
7.4 Case Study: Spell Checker 373
7.5 Exercises   384
7.6 Programming Assignments   385
Bibliography   389

8 Graphs 391
8.1 Graph Representation 393
8.2 Graph Traversals 395
8.3 Shortest Paths 398
8.3.1 All-to-All Shortest Path Problem 405
8.4 Cycle Detection 408
8.4.1 Union-Find Problem 409
8.5 Spanning Trees 411
8.6 Connectivity 415
8.6.1 Connectivity in Undirected Graphs 415
8.6.2 Connectivity in Directed Graphs 418
8.7 Topological Sort 421
8.8 Networks 423
8.8.1 Maximum Flows 423
8.8.2 Maximum Flows of Minimum Cost 433
8.9 Matching 438
8.9.1 Stable Matching Problem 442
8.9.2 Assignment Problem 445
8.9.3 Matching in Nonbipartite Graphs 447
8.10 Eulerian and Hamiltonian Graphs 449
8.10.1 Eulerian Graphs 449
8.10.2 Hamiltonian Graphs 453
8.11 Graph Coloring 459
8.12 NP-Complete Problems in Graph Theory 462
8.12.1 The Clique Problem 462
8.12.2 The 3-Colorability Problem 463
8.12.3 The Vertex Cover Problem 465
8.12.4 The Hamiltonian Cycle Problem 466
8.13 Case Study: Distinct Representatives 467

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
x ■ Contents

8.14 Exercises   480
8.15 Programming Assignments   486
Bibliography   487

9 Sorting 491
9.1 Elementary Sorting Algorithms 492
9.1.1 Insertion Sort 492
9.1.2 Selection Sort 495
9.1.3 Bubble Sort 497
9.1.4 Comb Sort 500
9.2 Decision Trees 501
9.3 Efficient Sorting Algorithms 505
9.3.1 Shell Sort 505
9.3.2 Heap Sort 508
9.3.3 Quicksort 512
9.3.4 Mergesort 518
9.3.5 Radix Sort 521
9.3.6 Counting Sort 527
9.4 Sorting in the Standard Template Library 528
9.5 Concluding Remarks 532
9.6 Case Study: Adding Polynomials 534
9.7 Exercises   542
9.8 Programming Assignments   543
Bibliography   545

10 Hashing 548
10.1 Hash Functions 549
10.1.1 Division 549
10.1.2 Folding 549
10.1.3 Mid-Square Function 550
10.1.4 Extraction 550
10.1.5 Radix Transformation 551
10.1.6 Universal Hash Functions 551
10.2 Collision Resolution 551
10.2.1 Open Addressing 552
10.2.2 Chaining 558
10.2.3 Bucket Addressing 560
10.3 Deletion 561
Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Contents ■ xi

10.4 Perfect Hash Functions 562


10.4.1 Cichelli’s Method 563
10.4.2 The FHCD Algorithm 566
10.5 Rehashing 568
10.5.1 The Cuckoo Hashing 568
10.6 Hash Functions for Extendible Files 571
10.6.1 Extendible Hashing 571
10.6.2 Linear Hashing 574
10.7 Case Study: Hashing with Buckets 576
10.8 Exercises   586
10.9 Programming Assignments   587
Bibliography   588

11 Data Compression 590


11.1 Conditions for Data Compression 590
11.2 Huffman Coding 592
11.2.1 Adaptive Huffman Coding 601
11.3 Run-Length Encoding 606
11.4 Ziv-Lempel Code 607
11.5 Case Study: Huffman Method with Run-Length Encoding 610
11.6 Exercises   622
11.7 Programming Assignments   622
Bibliography   624

12 Memory Management 625


12.1 The Sequential-Fit Methods 626
12.2 The Nonsequential-Fit Methods 627
12.2.1 Buddy Systems 629
12.3 Garbage Collection 636
12.3.1 Mark-and-Sweep 637
12.3.2 Copying Methods 644
12.3.3 Incremental Garbage Collection 646
12.3.4 Generational Garbage Collection 653
12.4 Concluding Remarks 657
12.5 Case Study: An In-Place Garbage Collector 658

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
xii ■ Contents

12.6 Exercises   667
12.7 Programming Assignments   668
Bibliography   671

13 String Matching 674


13.1 Exact String Matching 674
13.1.1 Straightforward Algorithms 674
13.1.2 The Knuth-Morris-Pratt Algorithm 677
13.1.3 The Boyer-Moore Algorithm 685
13.1.4 Multiple Searches 695
13.1.5 Bit-Oriented Approach 697
13.1.6 Matching Sets of Words 700
13.1.7 Regular Expression Matching 707
13.1.8 Suffix Tries and Trees 711
13.1.9 Suffix Arrays 717
13.2 Approximate String Matching 719
13.2.1 String Similarity 720
13.2.2 String Matching with k Errors 726
13.3 Case Study: Longest Common Substring 729
13.4 Exercises   738
13.5 Programming Assignments   740
Bibliography   741

Appendixes
A Computing Big-O 743
A.1 Harmonic Series 743
A.2 Approximation of the Function lg(n!) 743
A.3 Big-O for Average Case of Quicksort 745
A.4 Average Path Length in a Random Binary Tree 747
A.5 The Number of Nodes in an AVL Tree 748
B Algorithms in the Standard Template Library 749
B.1 Standard Algorithms 749
C NP-Completeness 758
C.1 Cook’s Theorem 758

Index 771

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Preface

The study of data structures, a fundamental component of a computer science edu-


cation, serves as the foundation upon which many other computer science fields are
built. Some knowledge of data structures is a must for students who wish to do work
in design, implementation, testing, or maintenance of virtually any software system.
The scope and presentation of material in Data Structures and Algorithms in C++
provide students with the necessary knowledge to perform such work.
This book highlights three important aspects of data structures. First, a very
strong emphasis is placed on the connection between data structures and their al-
gorithms, including analyzing algorithms’ complexity. Second, data structures are
presented in an object-oriented setting in accordance with the current design and
implementation paradigm. In particular, the information-hiding principle to ad-
vance encapsulation and decomposition is stressed. Finally, an important compo-
nent of the book is data structure implementation, which leads to the choice of C++
as the programming language.
The C++ language, an object-oriented descendant of C, is widespread in indus-
try and academia as an excellent programming language. It is also useful and natural
for introducing data structures. Therefore, because of the wide use of C++ in applica-
tion programming and the object-oriented characteristics of the language, using C++
to teach a data structures and algorithms course, even on the introductory level, is well
justified.
This book provides the material for an introductory data structures course,
as well as for an advanced data structures and algorithms course. It also meets the
requirements for the following units specified in the Computer Science Curriculum
2008: DS/GraphsAndTrees, PF/DataStructures, PF/Recursion, PF/ObjectOriented,
AL/BasicAnalysis, AL/AlgorithmicStrategies, AL/FundamentalAlgorithms,
AL/ PversusNP, PL/DeclarationsAndTypes, PL/AbstractionMechanisms, PL/
ObjectOrientedProgramming.
Most chapters include a case study that illustrates a complete context in which
certain algorithms and data structures can be used. These case studies were chosen
from different areas of computer science such as interpreters, symbolic computation,
and file processing, to indicate the wide range of applications to which topics under
discussion may apply.

xiii
Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
xiv ■ Preface

Brief examples of C++ code are included throughout the book to illustrate the
practical importance of data structures. However, theoretical analysis is equally im-
portant, so presentations of algorithms are integrated with analyses of efficiency.
Great care is taken in the presentation of recursion because even advanced stu-
dents have problems with it. Experience has shown that recursion can be explained
best if the run-time stack is taken into consideration. Changes to the stack are shown
when tracing a recursive function not only in the chapter on recursion, but also in
other chapters. For example, a surprisingly short function for tree traversal may re-
main a mystery if work done by the system on the run-time stack is not included in
the ­explanation. Standing aloof from the system and retaining only a purely theoreti-
cal perspective when discussing data structures and algorithms are not necessarily
helpful.
The thrust of this book is data structures, and other topics are treated here
only as much as necessary to ensure a proper understanding of this subject. Algo-
rithms are discussed from the perspective of data structures, so the reader will not
find a comprehensive discussion of different kinds of algorithms and all the facets
that a full presentation of algorithms requires. However, as mentioned, recursion
is covered in depth. In addition, complexity analysis of algorithms is presented in
some detail.
Chapters 1 and 3–8 present a number of different data structures and the algo-
rithms that operate on them. The efficiency of each algorithm is analyzed, and im-
provements to the algorithm are suggested.
■ Chapter 1 presents the basic principles of object-oriented programming, an intro-
duction to dynamic memory allocation and the use of pointers, and a rudimentary
presentation of the Standard Template Library (STL).
■ Chapter 2 describes some methods used to assess the efficiency of algorithms.
■ Chapter 3 presents different types of linked lists with an emphasis on their imple-
mentation with pointers.
■ Chapter 4 presents stacks and queues and their applications.
■ Chapter 5 contains a detailed discussion of recursion. Different types of recursion
are discussed, and a recursive call is dissected.
■ Chapter 6 discusses binary trees, including implementation, traversal, and search.
Balanced trees are also included in this chapter.
■ Chapter 7 details more generalized trees such as tries, 2– 4 trees, and B-trees.
■ Chapter 8 presents graphs.
Chapters 9–13 show different applications of data structures introduced in the
previous chapters. They emphasize the data structure aspects of each topic under
consideration.
■ Chapter 9 analyzes sorting in detail, and several elementary and nonelementary
methods are presented.
■ Chapter 10 discusses hashing, one of the most important areas in searching. Various
techniques are presented with an emphasis on the utilization of data structures.
■ Chapter 11 discusses data compression algorithms and data structures.

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Preface ■ xv

■ Chapter 12 presents various techniques and data structures for memory


­management.
■ Chapter 13 discusses many algorithms for exact and approximate string matching.
■ Appendix A discusses in greater detail big-O notation, introduced in Chapter 2.
■ Appendix B presents standard algorithms in the Standard Template Library.
■ Appendix C gives a proof of Cook’s theorem and illustrates it with an extended
example.
Each chapter contains a discussion of the material illustrated with appropriate
diagrams and tables. Except for Chapter 2, all chapters include a case study, which
is an extended example using the features discussed in that chapter. All case stud-
ies have been tested using the Visual C++ compiler on a PC and the g++ compiler
under Unix except the von Koch snowflake, which runs on a PC under Visual C++.
At the end of each chapter is a set of exercises of varying degrees of difficulty. Except
for Chapter 2, all chapters also include programming assignments and an up-to-date
bibliography of relevant literature.
Chapters 1– 6 (excluding Sections 2.9-10, 3.4, 6.4.3, 6.7-8, and 6.10-11) contain
the core material that forms the basis of any data structures course. These chapters
should be studied in sequence. The remaining six chapters can be read in any or-
der. A one-­semester course could include Chapters 1– 6, 9, and Sections 10.1 and
10.2. The entire book could also be part of a two-semester sequence.

Teaching Tools

The following instructor support materials are available when this book is used
in a classroom setting. All instructor teaching tools are available for download at
login.cengage.com.
Electronic Solution’s Manual. The Solution’s Manual that accompanies this textbook
includes complete solutions to all text exercises.
Electronic Figure Files. All images from the text are available for use in classroom
presentations.
PowerPoint Presentations. PowerPoint slides accompany each chapter. Slides may be
used to guide classroom presentation, to make available for students for chapter review,
or to print as classroom handouts. Instructors are encouraged to customize the slides to
suit their course needs.

Student Resources

Source Code. The source code for the text example programs is available for down-
load at cengagebrain.com and via the author’s Web site at http://www.mathcs.duq.
edu/drozdek/DSinCpp.

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
xvi ■ Preface

Changes in the Fourth Edition

The new edition primarily extends the old edition by including material on new topics
that are currently not covered. The additions include
■ A section on treaps (6.10) and a section on k-d trees (6.11)
■ A section on k-d B-trees (7.1.5)
■ A discussion of two additional sorting methods (Sections 9.1.3.1, 9.3.6)
■ A new hashing technique (Section 10.5.1)
■ A section on generational garbage collection (12.3.4)
There are also many small modifications and additions throughout the book.

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Object-Oriented
Programming
Using C++
1
© Cengage Learning 2013

1.1 Abstract Data Types


Before a program is written, we should have a fairly good idea of how to accom-
plish the task being implemented by this program. Hence, an outline of the program
­containing its requirements should precede the coding process. The larger and more
complex the project, the more detailed the outline phase should be. The implemen-
tation details should be delayed to the later stages of the project. In particular, the
details of the particular data structures to be used in the implementation should not
be ­specified at the beginning.
From the start, it is important to specify each task in terms of input and output.
At the beginning stages, we should be more concerned with what the program should
do, not how it should or could be done. Behavior of the program is more important
than the gears of the mechanism accomplishing it. For example, if an item is needed
to accomplish some tasks, the item is specified in terms of operations performed on it
rather than in terms of its inner structure. These operations may act upon this item,
for example, modifying it, searching for some details in it, or storing something in
it. After these operations are precisely specified, the implementation of the program
may start. The implementation decides which data structure should be used to make
execution most efficient in terms of time and space. An item specified in terms of op-
erations is called an abstract data type. An abstract data type is not a part of a program,
because a program written in a programming language requires the definition of
a data structure, not just the operations on the data structure. However, an object-
oriented language (OOL) such as C++ has a direct link to abstract data types by im-
plementing them as a class.

1.2 Encapsulation
Object-oriented programming (OOP) revolves around the concept of an object.
­Objects, however, are created using a class definition. A class is a template in accor-
dance to which objects are created. A class is a piece of software that includes a data

1
Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
2 ■ Chapter 1 Object-Oriented Programming Using C++

specification and functions operating on these data and possibly on the data belong-
ing to other class instances. Functions defined in a class are called methods, member
functions, or function members, and variables used in a class are called data members
(more properly, they should be called datum members). This combining of the data
and related operations is called data encapsulation. An object is an instance of a class,
an entity created using a class definition.
In contradistinction to functions in languages that are not object-oriented, ob-
jects make the connection between data and member functions much tighter and
more meaningful. In languages that are not object-oriented, declarations of data and
definitions of functions can be interspersed through the entire program, and only
the program documentation indicates that there is a connection between them. In
OOLs, a connection is established right at the outset; in fact, the program is based
on this connection. An object is defined by related data and operations, and because
there may be many objects used in the same program, the objects communicate by
exchanging messages that reveal as little detail about their internal structure as neces-
sary for adequate communication. Structuring programs in terms of objects allows us
to accomplish several goals.
First, this strong coupling of data and operations can be used much better in
modeling a fragment of the world, which is emphasized especially by software engi-
neering. Not surprisingly, OOP has its roots in simulation; that is, in modeling real-
world events. The first OOL was called Simula, and it was developed in the 1960s
in Norway.
Second, objects allow for easier error finding because operations are localized to
the confines of their objects. Even if side effects occur, they are easier to trace.
Third, objects allow us to conceal certain details of their operations from other
objects so that these operations may not be adversely affected by other objects. This
is known as the information-hiding principle. In languages that are not object-ori-
ented, this principle can be found to some extent in the case of local variables, or
as in Pascal, in local functions or procedures, which can be used and accessed only
by the function defining them. This is, however, a very tight hiding or no hiding at
all. Sometimes we may need to use (again, as in Pascal) a function f 2 defined in f 1
outside of f 1, but we cannot. Sometimes we may need to access some data local to
f 1 without exactly knowing the structure of these data, but we cannot. Hence, some
modification is needed, and it is accomplished in OOLs.
An object in OOL is like a watch. As users, we are interested in what the hands
show, but not in the inner workings of the watch. We are aware that there are gears
and springs inside the watch, but because we usually know very little about why all
these parts are in a particular configuration, we should not have access to this mecha-
nism so that we do not damage it, inadvertently or on purpose. This mechanism is
hidden from us, we have no immediate access to it, and the watch is protected and
works better than when its mechanism is open for everyone to see.
An object is like a black box whose behavior is very well defined, and we use the
object because we know what it does, not because we have an insight into how it does
it. This opacity of objects is extremely useful for maintaining them independently of
each other. If communication channels between the objects are well defined, then
changes made inside an object can affect other objects only as much as these changes
affect the communication channels. Knowing the kind of information sent out and

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Section 1.2 Encapsulation ■ 3

received by an object, the object can be replaced more easily by another object more
suitable in a particular situation; a new object can perform the same task differently
but more quickly in a certain hardware environment. An object discloses only as
much as is needed for the user to utilize it. It has a public part that can be accessed by
any user when the user sends a message matching any of the member function names
revealed by the object. In this public part, the object displays to the user buttons that
can be pushed to invoke the object's operations. The user knows only the names of
these operations and the expected behavior.
Information hiding tends to blur the dividing line between data and operations.
In Pascal-like languages, the distinction between data and functions or procedures is
clear and rigid. They are defined differently and their roles are very distinct. OOLs
put data and methods together, and to the user of the object, this distinction is much
less noticeable. To some extent, this incorporates the features of functional lan-
guages. LISP, one of the earliest programming languages, allows the user to treat data
and functions similarly, because the structure of both is the same.
We have already made a distinction between particular objects and object types
or classes. We write functions to be used with different variables, and by analogy, we
do not like to be forced to write as many object declarations as the number of objects
required by the program. Certain objects are of the same type and we would like only
to use a reference to a general object specification. For single variables, we make a
distinction between type declaration and variable declaration. In the case of objects,
we have a class declaration and object instantiation. For instance, in the following
class declaration, C is a class and object1 through object3 are objects.
class C {
public:
C(char *s = "", int i = 0, double d = 1) {
strcpy(dataMember1,s);
dataMember2 = i;
dataMember3 = d;
}
void memberFunction1() {
cout << dataMember1 << ' ' << dataMember2 << ' '
<< dataMember3 << endl;
}
void memberFunction2(int i, char *s = "unknown") {
dataMember2 = i;
cout << i << " received from " << s << endl;
}
protected:
char dataMember1[20];
int dataMember2;
double dataMember3;
};

C object1("object1",100,2000), object2("object2"), object3;

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
4 ■ Chapter 1 Object-Oriented Programming Using C++

Message passing is equivalent to a function call in traditional languages. ­However,


to stress the fact that in OOLs the member functions are relative to ­objects, this new
term is used. For example, the call to public memberFunction1() in object1,
object1.memberFunction1();

is seen as message memberFunction1() sent to object1. Upon receiving the mes-


sage, the object invokes its member function and displays all relevant information.
Messages can include parameters so that
object1.memberFunction2(123);

is the message memberFunction2() with parameter 123 received by object1.


The lines containing these messages are either in the main program, in a func-
tion, or in a member function of another object. Therefore, the receiver of the mes-
sage is identifiable, but not necessarily the sender. If object1 receives the message
memberFunction1(), it does not know where the message originated. It only re-
sponds to it by displaying the information memberFunction1() encapsulates. The
same goes for memberFunction2(). Therefore, the sender may prefer sending a
message that also includes its identification, as follows:
object1.memberFunction2(123, "object1");

A powerful feature of C++ is the possibility of declaring generic classes by using


type parameters in the class declaration. For example, if we need to declare a class
that uses an array for storing some items, then we may declare this class as
class intClass {
int storage[50];
..................
};

However, in this way, we limit the usability of this class to integers only; if we
need a class that performs the same operations as intClass except that it operates
on float numbers, then a new declaration is needed, such as
class floatClass {
float storage[50];
..................
};

If storage is to hold structures, or pointers to characters, then two more classes


must be declared. It is much better to declare a generic class and decide what type of
items the object is referring to only when defining the object. Fortunately, C++ al-
lows us to declare a class in this way, and the declaration for the example is
template<class genType>
class genClass {
genType storage[50];
...................
};

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Section 1.2 Encapsulation ■ 5

Later, we make the decision about how to initialize genType:


genClass<int> intObject;
genClass<float> floatObject;

This generic class becomes a basis for generating two new classes, genClass
of int and genClass of float, and then these two classes are used to create two
­objects, intObject and floatObject. In this way, the generic class manifests it-
self in different forms depending on the specific declaration. One generic declaration
­suffices for enabling such different forms.
We can go even further than that by not committing ourselves to 50 cells in
storage and by delaying that decision until the object definition stage. But just in
case, we may leave a default value so that the class declaration is now
template<class genType, int size = 50>
class genClass {
genType storage[size];
..................
};

The object definition is now


genClass<int> intObject1; // use the default size;
genClass<int,100> intObject2;
genClass<float,123> floatObject;

This method of using generic types is not limited to classes only; we can use
them in function declarations as well. For example, the standard operation for swap-
ping two values can be defined by the function
template<class genType>
void swap(genType& el1, genType& el2) {
genType tmp = el1; el1 = el2; el2 = tmp;
}

This example also indicates the need for adapting built-in operators to spe-
cific situations. If genType is a number, a character, or a structure, then the as-
signment operator, =, performs its function properly. But if genType is an array,
then we can expect a problem in swap(). The problem can be resolved by over-
loading the assignment operator by adding to it the functionality required by a
specific data type.
After a generic function has been declared, a proper function can be generated at
compilation time. For example, if the compiler sees two calls,
swap(n,m); // swap two integers;
swap(x,y); // swap two floats;

it generates two swap functions to be used during execution of the program.

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
6 ■ Chapter 1 Object-Oriented Programming Using C++

1.3 Inheritance
OOLs allow for creating a hierarchy of classes so that objects do not have to be in-
stantiations of a single class. Before discussing the problem of inheritance, consider
the following class definitions:
class BaseClass {
public:
BaseClass() { }
void f(char *s = "unknown") {
cout << "Function f() in BaseClass called from " << s << endl;
h();
}
protected:
void g(char *s = "unknown") {
cout << "Function g() in BaseClass called from " << s << endl;
}
private:
void h() {
cout << "Function h() in BaseClass\n";
}
};
class Derived1Level1 : public virtual BaseClass {
public:
void f(char *s = "unknown") {
cout << "Function f() in Derived1Level1 called from " << s << endl;
g("Derived1Level1");
h("Derived1Level1");
}
void h(char *s = "unknown") {
cout << "Function h() in Derived1Level1 called from " << s << endl;
}
};
class Derived2Level1 : public virtual BaseClass {
public:
void f(char *s = "unknown") {
cout << "Function f() in Derived2Level1 called from " << s << endl;
g("Derived2Level1");
// h(); // error: BaseClass::h() is not accessible
}
};
class DerivedLevel2 : public Derived1Level1, public Derived2Level1 {
public:
void f(char *s = "unknown") {
cout << "Function f() in DerivedLevel2 called from " << s << endl;
g("DerivedLevel2");

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Section 1.3 Inheritance ■ 7

Derived1Level1::h("DerivedLevel2");
BaseClass::f("DerivedLevel2");
}
};
A sample program is
int main() {
BaseClass bc;
Derived1Level1 d1l1;
Derived2Level1 d2l1;
DerivedLevel2 dl2;
bc.f("main(1)");
// bc.g(); // error: BaseClass::g() is not accessible
// bc.h(); // error: BaseClass::h() is not accessible
d1l1.f("main(2)");
// d1l1.g(); // error: BaseClass::g() is not accessible
d1l1.h("main(3)");
d2l1.f("main(4)");
// d2l1.g(); // error: BaseClass::g() is not accessible
// d2l1.h(); // error: BaseClass::h() is not accessible
dl2.f("main(5)");
// dl2.g(); // error: BaseClass::g() is not accessible
dl2.h();
return 0;
}

This sample produces the following output:


Function f() in BaseClass called from main(1)
Function h() in BaseClass
Function f() in Derived1Level1 called from main(2)
Function g() in BaseClass called from Derived1Level1
Function h() in Derived1Level1 called from Derived1Level1
Function h() in Derived1Level1 called from main(3)
Function f() in Derived2Level1 called from main(4)
Function g() in BaseClass called from Derived2Level1
Function f() in DerivedLevel2 called from main(5)
Function g() in BaseClass called from DerivedLevel2
Function h() in Derived1Level1 called from DerivedLevel2
Function f() in BaseClass called from DerivedLevel2
Function h() in BaseClass
Function h() in Derived1Level1 called from unknown

The class BaseClass is called a base class or a superclass, and other classes are called
subclasses or derived classes because they are derived from the superclass in that they can
use the data members and member functions specified in BaseClass as protected or
public. They inherit all these members from their base class so that they do not have
to repeat the same definitions. However, a derived class can override the ­definition of a

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
8 ■ Chapter 1 Object-Oriented Programming Using C++

member function by introducing its own definition. In this way, both the base class and
the derived class have some measure of control over their member functions.
The base class can decide which member functions and data members can be re-
vealed to derived classes so that the principle of information hiding holds not only with
respect to the user of the base class, but also to the derived classes. Moreover, the derived
class can decide which parts of the public and protected member functions and data
members to retain and use and which to modify. For example, both ­Derived1Level1
and Derived2Level1 define their own versions of f(). However, the access to the
member function with the same name in any of the classes higher up in the hierarchy is
still possible by preceding the function with the name of the class and the scope opera-
tor, as shown in the call of BaseClass::f() from f() in DerivedLevel2.
A derived class can add some new members of its own. Such a class can become
a base class for other classes that can be derived from it so that the inheritance hierar-
chy can be deliberately extended. For example, the class Derived1Level1 is derived
from BaseClass, but at the same time, it is the base class for DerivedLevel2.
Inheritance in our examples is specified as public by using the word public
after the semicolon in the heading of the definition of a derived class. Public inheri-
tance means that public members of the base class are also public in the derived class,
and protected members are also protected. In the case of protected inheritance (with
the word protected in the heading of the definition), both public and protected
members of the base class become protected in the derived class. Finally, for private
inheritance, both public and protected members of the base class become private in
the derived class. In all types of inheritance, private members of the base class are
inaccessible to any of the derived classes. For example, an attempt to call h() from
f() in Derived2Level1 causes a compilation error, “BaseClass::h() is not ac-
cessible.” However, a call of h() from f() in Derived1Level1 causes no problem
because it is a call to h() defined in Derived1Level1.
Protected members of the base class are accessible only to derived classes
and not to nonderived classes. For this reason, both Derived1Level1 and
Derived2Level1 can call BaseClass's protected member function g(), but a call
to this function from main() is rendered illegal.
A derived class does not have to be limited to one base class only. It can be
derived from more than one base class. For example, DerivedLevel2 is defined
as a class derived from both Derived1Level1 and Derived2Level1, inheriting
in this way all the member functions of Derived1Level1 and Derived2Level1.
However, DerivedLevel2 also inherits the same member functions from Base-
Class twice because both classes used in the definition of DerivedLevel2
are derived from BaseClass. This is redundant at best, and at worst can
cause a ­c ompilation error, "member is ambiguous BaseClass::g() and
­B aseClass::g(). " To prevent this from happening, the definitions of the
two classes include the modifier virtual, which means that DerivedLevel2
­c ontains only one copy of each member function from BaseClass. A simi-
lar problem arises if f() in D ­ erivedLevel2 calls h() without the preceding
scope operator and class name, ­D erived1Level1::h(). It does not matter
that h() is private in BaseClass and inaccessible to DerivedLevel2 . An
error would be printed, "member is ambiguous Derived1Level1::h() and
­ aseClass::h()."
B

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Section 1.4 Pointers ■ 9

1.4 Pointers
Variables used in a program can be considered as boxes that are never empty; they
are filled with some content either by the programmer or, if uninitialized, by the op-
erating system. Such a variable has at least two attributes: the content or value and the
­location of the box or variable in computer memory. This content can be a number,
a character, or a compound item such as a structure or union. However, this content
can also be the location of another variable; variables with such contents are called
pointers. Pointers are usually auxiliary variables that allow us to access the values
of other variables indirectly. A pointer is analogous to a road sign that leads us to
a ­certain location or to a slip of paper on which an address has been jotted down.
They are variables leading to variables, humble auxiliaries that point to some other
­variables as the focus of attention.
For example, in the declaration
int i = 15, j, *p, *q;

i and j are numerical variables and p and q are pointers to numbers; the star in
front of p and q indicates their function. Assuming that the addresses of the variables
i, j, p, and q are 1080, 1082, 1084, and 1086, then after assigning 15 to i in the
declaration, the positions and values of the variables in computer memory are as in
Figure 1.1a.
Now, we could make the assignment p = i (or p = (int*) i if the compiler
does not accept it), but the variable p was created to store the address of an integer
variable, not its value. Therefore, the proper assignment is p = &i, where the am-
persand in front of i means that the address of i is meant and not its content. Figure
1.1b illustrates this situation. In Figure 1.1c, the arrow from p to i indicates that p is
a pointer that holds the address of i.
We have to be able to distinguish the value of p, which is an address, from the
value of the location whose address the pointer holds. For example, to assign 20 to
the variable pointed to by p, the assignment statement is
*p = 20;

The star (*) here is an indirection operator that forces the system to first retrieve
the contents of p, then access the location whose address has just been retrieved from
p, and only afterward, assign 20 to this location (Figure 1.1d). Figures 1.1e through
1.1n give more examples of assignment statements and how the values are stored in
computer memory.
In fact, pointers—like all variables—also have two attributes: a content and a lo-
cation. This location can be stored in another variable, which then becomes a pointer
to a pointer.
In Figure 1.1, addresses of variables were assigned to pointers. Pointers can, how-
ever, refer to anonymous locations that are accessible only through their ­addresses
and not—like variables—by their names. These locations must be set aside by the
memory manager, which is performed dynamically during the run of the program,
unlike for variables, whose locations are allocated at compilation time.

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
10 ■ Chapter 1 Object-Oriented Programming Using C++

Figure 1.1 Changes of values after assignments are made using pointer variables. Note that (b)
and (c) show the same situation, and so do (d) and (e), (g) and (h), (i) and (j), (k) and
(l), and (m) and (n).

i j p q
int i = 15, j,
15 ? ? ? (a)
*p, *q; 1080 1082 1084 1086
i j p q
p = &i; 15 ? 1080 ? (b)
1080 1082 1084 1086
p i
15 (c)
i j p q
*p = 20; 20 ? 1080 ? (d)
1080 1082 1084 1086
p i
20 (e)
i j p q
j = 2 * *p; 20 40 1080 ? (f)
1080 1082 1084 1086
i j p q
q = &i; 20 40 1080 1080 (g)
1080 1082 1084 1086
p i
20 (h)
q

i j p q
*p = *q – 1; 19 40 1080 1080 (i)
1080 1082 1084 1086
To dynamically allocate and deallocate memory, two functions are used. One
p as muchi space as needed to store an object whose
function, new, takes from memory
19
type follows new. For example, with the instruction (j)
q
p = new int;

the program requests enough space to store


i one
j integer,
p from q the memory manager,
and theq address
= &j; of the beginning of this
19 portion
40 of 1080
memory is stored in p.(k)
1082 Now the
values can be ­assigned to the memory1080
block pointed
1082 1084to by p1086
only indirectly through a
pointer, either pointer p or anypother pointer
i q that was assigned the address stored
in p with the assignment q = p. 19 (l)
If the space occupied by theq integer accessible
j from p is no longer needed, it can
be returned to the pool of free memory locations
40 managed by the operating system
by issuing the instruction
i j p q
delete p; 39 40 1080 1082 (m)
*p = *q – 1;
1080 1082 1084 1086
p i
Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
1080 1082 1084 1086
i j p q
q = &i; 20 40 S e c t i o n1080
1080 1 . 4 P o i n t e r s (g)■ 11
1080 1082 1084 1086
p i
20 (h)
Figure 1.1 (continued)
q

i j p q
*p = *q – 1; 19 40 1080 1080 (i)
1080 1082 1084 1086
p i
19 (j)
q

i j p q
q = &j; 19 40 1080 1082 (k)
1080 1082 1084 1086
p i
19 (l)
q j
40

i j p q
*p = *q – 1; 39 40 1080 1082 (m)
1080 1082 1084 1086
p i
39 (n)
q j
40

However, after executing this statement, the beginning addresses of the released
­memory block are still in p, although the block, as far as the program is concerned,
does not exist anymore. It is like treating an address of a house that has been demol-
ished as the address of the existing location. If we use this address to find someone,
the result can be easily foreseen. Similarly, if after issuing the delete statement we
do not erase the address from the pointer variable participating in deletion, the re-
sult is potentially dangerous, and we can crash the program when trying to access
non­existing locations, particularly for more complex objects than numerical values.
This is the dangling reference problem. To avoid this problem, an address has to be
assigned to a pointer; if it cannot be the address of any location, it should be a null
address, which is simply 0. After execution of the assignment
p = 0;

we may not say that p refers to null or points to null but that p becomes null or p is null.
Another problem associated with delete is the memory leak. Consider the follow-
ing two lines of code:
p = new int;
p = new int;

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
12 ■ Chapter 1 Object-Oriented Programming Using C++

After allocating one cell for an integer, the same pointer p is used to allocate another
cell. After the second assignment, the first cell becomes inaccessible and also unavail-
able for subsequent memory allocations for the duration of the program. The problem
is with not releasing with delete the memory accessible from p before the second
assignment is made. The code should be:
p = new int;
delete p;
p = new int;

Memory leaks can become a serious problem when a program uses more and
more memory without releasing it, eventually exhausting memory and leading to ab-
normal termination. This is especially important in programs that are executed for a
long time, such as programs in servers.

1.4.1 Pointers and Arrays


In the previous section, the pointer p refers to a block of memory that holds one inte-
ger. A more interesting situation is when a pointer refers to a data structure that is
created and modified dynamically. This is a situation where we would need to over-
come the restrictions imposed by arrays. Arrays in C++, and in most programming
languages, have to be declared in advance; therefore, their sizes have to be known
before the program starts. This means that the programmer needs a fair knowledge
of the problem being programmed to choose the right size for the array. If the size
is too big, then the array unnecessarily occupies memory space, which is basically
wasted. If the size is too small, the array can overflow with data and the program
will abort. Sometimes the size of the array simply cannot be predicted; therefore,
the decision is delayed until run time, and then enough memory is allocated to hold
the array.
The problem is solved with the use of pointers. Consider Figure 1.1b. In this fig-
ure, pointer p points to location 1080. But it also allows accessing of locations 1082,
1084, and so forth because the locations are evenly spaced. For example, to access the
value of variable j, which is a neighbor of i, it is enough to add the size of an integer
variable to the address of i stored in p to access the value of j, also from p. And this
is basically the way C++ handles arrays.
Consider the following declarations:
int a[5], *p;

The declarations specify that a is a pointer to a block of memory that can hold
five integers. The pointer a is fixed; that is, a should be treated as a constant so that
any attempt to assign a value to a, as in
a = p;

or in
a++;

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Section 1.4 Pointers ■ 13

is considered a compilation error. Because a is a pointer, pointer notation can be


used to access cells of the array a. For example, an array notation used in the loop
that adds all the numbers in a,
for (sum = a[0], i = 1; i < 5; i++)
sum += a[i];
can be replaced by a pointer notation
for (sum = *a, i = 1; i < 5; i++)
sum += *(a + i);
or by
for (sum = *a, p = a+1; p < a+5; p++)
sum += *p;
Note that a+1 is a location of the next cell of the array a so that a+1 is equivalent to
&a[1]. Thus, if a equals 1020, then a+1 is not 1021 but 1022 because pointer arith-
metic depends on the type of pointed entity. For example, after declarations
char b[5];
long c[5];
and assuming that b equals 1050 and c equals 1055, b+1 equals 1051 because one
character occupies 1 byte, and c+1 equals 1059 because one long number occupies
4 bytes. The reason for these results of pointer arithmetic is that the expression c+i
denotes the memory address c+i*sizeof(long).
In this discussion, the array a is declared statically by specifying in its declara-
tion that it contains five cells. The size of the array is fixed for the duration of the pro-
gram run. But arrays can also be declared dynamically. To that end, pointer variables
are used. For example, the assignment
p = new int[n];

allocates enough room to store n integers. Pointer p can be treated as an array vari-
able so that array notation can be used. For example, the sum of numbers in the array
p can be found with the code that uses array notation,

for (sum = p[0], i = 1; i < n; i++)


sum += p[i];

a pointer notation that is a direct rendition of the previous loop,


for (sum = *p, i = 1; i < n; i++)
sum += *(p+i);

or a pointer notation that uses two pointers,


for (sum = *p, q = p+1; q < p+n; q++)
sum += *q;

Because p is a variable, it can be assigned a new array. But if the array ­currently
pointed to by p is no longer needed, it should be disposed of by the ­instruction
delete [] p;

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
14 ■ Chapter 1 Object-Oriented Programming Using C++

Note the use of empty brackets in the instruction. The brackets indicate that p points
to an array. Also, delete should be used with pointers that were assigned a value
with new. For this reason, the two following applications of delete are very likely
to lead to a program crash:
int a[10], *p = a;
delete [] p;
int n = 10, *q = &n;
delete q;

A very important type of array is a string, or an array of characters. Many pre­


defined functions operate on strings. The names of these functions start with str, as
in strlen(s) to find the length of the string s or strcpy(s1,s2) to copy string
s2 to s1. It is important to remember that all these functions assume that strings
end with the null character '\0'. For example, strcpy(s1,s2) continues copying
until it finds this character in s2. If a programmer does not ­include this character in
s2, copying stops when the first occurrence of this character is found somewhere in
computer memory after location s2. This means that copying is performed to loca-
tions outside s1, which eventually may lead the ­program to crash.

1.4.2 Pointers and Copy Constructors


Some problems can arise when pointer data members are not handled properly when
copying data from one object to another. Consider the following definition:
struct Node {
char *name;
int age;
Node(char *n = "", int a = 0) {
name = strdup(n);
age = a;
}
};

The intention of the declarations


Node node1("Roger",20), node2(node1); //or node2 = node1;

is to create object node1, assign values to the two data members in node1, and then
create object node2 and initialize its data members to the same values as in node1.
These objects are to be independent entities so that assigning values to one of them
should not affect values in the other. However, after the assignments
strcpy(node2.name,"Wendy");
node2.age = 30;

the printing statement


cout<<node1.name<<' '<<node1.age<<' '<<node2.name<<' '<<node2.age;

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Section 1.4 Pointers ■ 15

Figure 1.2 Illustrating the necessity of using a copy constructor for objects with pointer
members.

node1 node1
name { R o g e r \0 W e n d y \0
age { 20 20
node2 node2
name {
age { 20 30
(a) (b)

node1 node1
R o g e r \0 R o g e r \0
20 20
node2 node2
R o g e r \0 W e n d y \0
20 30
(c) (d)

generates the output


Wendy 30 Wendy 20

The ages are different, but the names in the two objects are the same. What happened?
The problem is that the definition of Node does not provide a copy constructor
Node(const Node&);
which is necessary to execute the declaration node2(node1) to initialize node1.
If a user copy constructor is missing, the constructor is generated automatically by
the compiler. But the compiler-generated copy constructor performs member-by-
member copying. Because name is a pointer, the copy constructor copies the string
address node1.name to node2.name, not the string content, so that right after ex-
ecution of the declaration, the situation is as in Figure 1.2a. Now if the assignments
strcpy(node2.name,"Wendy");
node2.age = 30;

are executed, node2.age is properly updated, but the string "Roger" pointed to by
the name member of both objects is overwritten by "Wendy", which is also pointed
to by the two pointers (Figure 1.2b). To prevent this from happening, the user must
define a proper copy constructor, as in

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
16 ■ Chapter 1 Object-Oriented Programming Using C++

struct Node {
char *name;
int age;
Node(char *n = 0, int a = 0) {
name = strdup(n);
age = a;
}
Node(const Node& n) { // copy constructor;
name = strdup(n.name);
age = n.age;
}
};

With the new constructor, the declaration node2(node1) generates another copy
of "Roger" pointed to by node2.name (Figure 1.2c), and the assignments to data
members in one object have no effect on members in the other object, so that after
­execution of the assignments
strcpy(node2.name,"Wendy");
node2.age = 30;

the object node1 remains unchanged, as illustrated in Figure 1.2d.


Note that a similar problem is raised by the assignment operator. If a definition
of the assignment operator is not provided by the user, an assignment
node1 = node2;

performs member-by-member copying, which leads to the same problem as in Fig-


ure 1.2a–b. To avoid the problem, the assignment operator has to be overloaded by
the user. For Node, the overloading is accomplished by
Node& operator=(const Node& n) {
if (this != &n) { // no assignment to itself;
if (name != 0)
free(name);
name = strdup(n.name);
age = n.age;
}
return *this;
}

In this code, a special pointer this is used. Each object can access its own ad-
dress through the pointer this so that *this is the object itself.

1.4.3 Pointers and Destructors


What happens to locally defined objects of type Node? Like all local items, they are
destroyed in the sense that they become unavailable outside the block in which they
are defined, and memory occupied by them is also released. But although memory oc-
cupied by an object of type Node is released, not all the memory related to this ­object

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Section 1.4 Pointers ■ 17

becomes available. One of the data members of this object is a pointer to a string;
therefore, memory occupied by the pointer data member is released, but memory
taken by the string is not. After the object is destroyed, the string previously avail-
able from its data member name becomes inaccessible (if not assigned to the name of
some other object or to a string variable) and memory occupied by this string can no
longer be released, which leads to a memory leak. This is a problem with objects that
have data members pointing to dynamically allocated locations. To avoid the prob-
lem, the class definition should include a definition of a destructor. A destructor is a
function that is automatically invoked when an object is destroyed, which takes place
upon exit from the block in which the object is defined or upon the call of delete.
Destructors take no ­arguments and return no values so that there can be only one
destructor per class. For the class Node, a destructor can be defined as
~Node() {
if (name != 0)
free(name);
}

1.4.4 Pointers and Reference Variables


Consider the following declarations:
int n = 5, *p = &n, &r = n;

Variable p is declared as being of type int*, a pointer to an integer, and r is of type


int&, an integer reference variable. A reference variable must be initialized in its decla-
ration as a reference to a particular variable, and this reference cannot be changed. This
means that a reference variable cannot be null. A reference variable r can be consid-
ered a different name for a variable n so that if n changes then r changes as well. This is
­because a reference variable is implemented as a constant pointer to the variable.
After the three declarations, the printing statement
cout << n << ' ' << *p << ' ' << r << endl;
outputs 5 5 5. After the assignment
n = 7;

the same printing statement outputs 7 7 7. Also, an assignment


*p = 9;

gives the output 9 9 9, and the assignment


r = 10;

leads to the output 10 10 10. These statements indicate that in terms of notation, what
we can accomplish with dereferencing of pointer variables is accomplished without
dereferencing of reference variables. This is no accident because, as mentioned, refer-
ence variables are implemented as constant pointers. Instead of the declaration
int& r = n;

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
18 ■ Chapter 1 Object-Oriented Programming Using C++

we can use a declaration


int *const r = &n;

where r is a constant pointer to an integer, which means that the assignment


r = q;

where q is another pointer, is an error because the value of r cannot change. How-
ever, the assignment
*r = 1;

is acceptable if n is not a constant integer.


It is important to note the difference between the type int *const and the type
const int *. The latter is a type of pointer to a constant integer:

const int *s = &m;

after which the assignment


s = &m;

where m in an integer (whether constant or not) is admissible, but the assignment


*s = 2;

is erroneous, even if m is not a constant.


Reference variables are used in passing arguments by reference to function calls.
Passing by reference is required if an actual parameter should be changed perma-
nently during execution of a function. This can be accomplished with pointers (and
in C, this is the only mechanism available for passing by reference) or with reference
variables. For example, after declaring a function
void f1(int i, int* j, int& k) {
i = 1;
*j = 2;
k = 3;
}

the values of the variables


int n1 = 4, n2 = 5, n3 = 6;

after executing the call


f1(n1,&n2,n3);

are n1 = 4, n2 = 2, n3 = 3.
Reference type is also used in indicating the return type of functions. For ex-
ample, having defined the function
int& f2(int a[], int i) {
return a[i];
}

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Section 1.4 Pointers ■ 19

and declaring the array


int a[] = {1,2,3,4,5};

we can use f2() on any side of the assignment operator. For instance, on the right-
hand side,
n = f2(a,3);

or on the left-hand side,


f2(a,3) = 6;

which assigns 6 to a[3] so that a = [1 2 3 6 5]. Note that we can accomplish the same
with pointers, but dereferencing has to be used explicitly:
int* f3(int a[], int i) {
return &a[i];
}

and then
*f3(a,3) = 6;

Reference variables and the reference return type have to be used with caution
­ ecause there is a possibility of compromising the information-hiding principle
b
when they are used improperly. Consider class C:
class C {
public:
int& getRefN() {
return n;
}
int getN() {
return n;
}
private:
int n;
} c;

and these assignments:


int& k = c.getRefN();
k = 7;
cout << c.getN();

Although n is declared private, after the first assignment it can be accessed at will
from the outside through k and assigned any value. An assignment can also be made
through getRefN():
c.getRefN() = 9;

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
20 ■ Chapter 1 Object-Oriented Programming Using C++

1.4.5 Pointers to Functions


As indicated in Section 1.4.1, one of the attributes of a variable is its address indi-
cating its position in computer memory. The same is true for functions: One of the
­attributes of a function is the address indicating the location of the body of the func-
tion in memory. Upon a function call, the system transfers control to this location
to execute the function. For this reason, it is possible to use pointers to functions.
These pointers are very useful in implementing functionals (that is, functions that
take functions as arguments) such as an integral.
Consider a simple function:
double f(double x) {
return 2*x;
}

With this definition, f is the pointer to the function f(), *f is the function itself, and
(*f)(7) is a call to the function.
Consider now writing a C++ function that computes the following sum:

a f1i2
m

i5n

To compute the sum, we have to supply not only limits n and m, but also a func-
tion f. Therefore, the desired implementation should allow for passing numbers
not only as arguments, but also as functions. This is done in C++ in the following
­fashion:
double sum(double (*f)(double), int n, int m) {
double result = 0;
for (int i = n; i <= m; i++)
result += f(i);
return result;
}

In this definition of sum(), the declaration of the first formal argument


double (*f)(double)

means that f is a pointer to a function with one double argument and a double return
value. Note the need for parentheses around *f. Because parentheses have prece-
dence over the dereference operator *, the expression
double *f(double)

declares a function that returns a pointer to a double value.


The function sum() can be called now with any built-in or user-defined double
function that takes one double argument, as in
cout << sum(f,1,5) << endl;
cout << sum(sin,3,7) << endl;

Another example is a function that finds a root of a continuous function in an


interval. The root is found by repetitively bisecting an interval and finding a ­midpoint

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Section 1.5 Polymorphism ■ 21

of the current interval. If the function value at the midpoint is zero or the interval is
smaller than some small value, the midpoint is returned. If the values of the function
on the left limit of the current interval and on the midpoint have ­opposite signs, the
search continues in the left half of the current interval; otherwise, the current interval
becomes its right half. Here is an implementation of this algorithm:
double root(double (*f)(double), double a, double b, double epsilon) {
double middle = (a + b) / 2;
while (f(middle) != 0 && fabs(b - a) > epsilon) {
if (f(a) * f(middle) < 0) // if f(a) and f(middle) have
b = middle; // opposite signs;
else a = middle;
middle = (a + b) / 2;
}
return middle;
}

1.5 Polymorphism
Polymorphism refers to the ability of acquiring many forms. In the context of OOP
this means that the same function name denotes many functions that are members of
different objects. Consider the following example:
class Class1 {
public:
virtual void f() {
cout << "Function f() in Class1\n";
}
void g() {
cout << "Function g() in Class1\n";
}
};
class Class2 {
public:
virtual void f() {
cout << "Function f() in Class2\n";
}
void g() {
cout << "Function g() in Class2\n";
}
};
class Class3 {
public:
virtual void h() {
cout << "Function h() in Class3\n";
}
};

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
22 ■ Chapter 1 Object-Oriented Programming Using C++

int main() {
Class1 object1, *p;
Class2 object2;
Class3 object3;
p = &object1;
p->f();
p->g();
p = (Class1*) &object2;
p->f();
p->g();
p = (Class1*) &object3;
p->f(); // possibly abnormal program termination;
p->g();
// p->h(); // h() is not a member of Class1;
return 0;
}

The output of this program is as follows:


Function f() in Class1
Function g() in Class1
Function f() in Class2
Function g() in Class1
Function h() in Class3
Function g() in Class1

We should not be surprised that when p is declared as a pointer to object1 of


class type Class1, then the two function members are activated that are defined
in Class1. But after p becomes a pointer to object2 of class type Class2, then
p->f() activates a function defined in Class2, whereas p->g() activates a func-
tion defined in Class1. How is this possible? The difference lies in the moment at
which a decision is made about the function to be called.
In the case of the so-called static binding, the decision concerning a function to
be executed is determined at compilation time. In the case of dynamic binding, the de-
cision is delayed until run time. In C++, dynamic binding is enforced by declaring a
member function as virtual. In this way, if a virtual function ­member is called, then
the function chosen for execution depends not on the type of pointer determined by its
­declaration, but on the type of value the pointer ­currently has. In our example, pointer
p was declared to be of type Class1*. Therefore, if p points to function g() that is
not ­virtual, then regardless of the place in the program in which the call instruction
p‑>g()occurs, this is always con­sidered a call to the function g() defined in Class1.
This is due to the fact that the compiler makes this decision based on the type declara-
tion of p and the fact that g() is not ­virtual. For virtual function members the situ-
ation drastically changes. This time, the decision is made during run time: if a function
member is virtual, then the system looks at the type of the current pointer value and
­invokes the proper function member. After the initial declaration of p as being of type
Class1*, virtual function f() belonging to Class1 is called, whereas after assigning
to p the address of object2 of type Class2, f() belonging to Class2 is called.

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Section 1.6 C++ and Object-Oriented Programming ■ 23

Note that after p was assigned the address of object3, it still invokes g()de-
fined in Class1. This is because g() is not redefined in Class3 and g() from
Class1 is called. But an attempt to call p->f() results in a program crash—or gives
a wrong output since the C++ picks the first virtual function in Class3—because f()
is declared virtual in Class1 so the system tries to find, unsuccessfully, in Class3 a
definition of f(). Also, notwithstanding the fact that p points to object3, instruc-
tion p->h() results in a compilation error, because the compiler does not find h()
in Class1, where Class1* is still the type of pointer p. To the compiler, it does not
matter that h() is defined in Class3 (be it virtual or not).
Polymorphism is a powerful tool in OOP. It is enough to send a standard mes-
sage to many different objects without specifying how the message will be processed.
There is no need to know of what type the objects are. The receiver is responsible for
interpreting the message and following it. The sender does not have to modify the
­message depending on the type of receiver. There is no need for switch or if-else
statements. Also, new units can be added to a complex program without needing to
recompile the entire program.

1.6 C++ and Object-Oriented Programming

The previous discussion presumed that C++ is an OOL, and all the features of OOLs
that we discussed have been illustrated with C++ code. However, C++ is not a pure
OOL. C++ is more object-oriented than C or Pascal, which have no object-oriented
features, or Ada, which supports classes (packages) and instances; however, C++ is
less object-oriented than pure OOLs such as Smalltalk or Eiffel.
C++ does not enforce the object-oriented approach. We can program in C++
without knowing that such features are a part of the language. The reason for this is the
popularity of C. C++ is a superset of C, so a C programmer can easily switch to C++,
adapting only to its friendlier features such as I/O, call-by-reference mechanism, default
values for function parameters, operator overloading, inline functions, and the like. Us-
ing an OOL such as C++ does not guarantee that we are doing OOP. On the other hand,
invoking the entire machinery of classes and member functions may not always be nec-
essary, especially in small programs, so not enforcing OOP is not necessarily a disadvan-
tage. Also, C++ is easier to integrate with existing C code than other OOLs.
C++ has an excellent encapsulation facility that allows for well-controlled in-
formation hiding. There is, however, a relaxation to this rule in the use of so-called
friend functions. The problem is that private information of a certain class cannot
be ­accessed by anyone, and the public information is accessible to every user. But
sometimes we would like to allow only some users to have access to the private pool
of ­information. This can be accomplished if the class lists the user functions as its
friends. For example, if the definition is

class C {
int n;
friend int f();
} ob;

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
24 ■ Chapter 1 Object-Oriented Programming Using C++

function f() has direct access to variable n belonging to the class C, as in

int f ()
{ return 10 * ob.n; }

This could be considered a violation of the information-hiding principle; how-


ever, the class C itself grants the right to make public to some users what is private
and inaccessible to others. Thus, because the class has control over what to consider
a friend function, the friend function mechanism can be considered an extension of
the information-hiding principle. This mechanism, admittedly, is used to facilitate
programming and speed up execution, because rewriting code without using friend
functions can be a major problem. Such a relaxation of some rules is, by the way, not
uncommon in computer science; other examples include the existence of loops in
functional languages, such as LISP, or storing some information at the beginning of
data files in violation of the relational database model, as in dBaseIII+.

1.7 The Standard Template Library


C++ is an object-oriented language, but recent extensions to the language bring C++
to a higher level. The most significant addition to the language is the Standard Tem-
plate Library (STL), developed primarily by Alexander Stepanov and Meng Lee. The
library includes three types of generic entities: containers, iterators, and algorithms. Al-
gorithms are frequently used functions that can be applied to different data structures.
The application is mediated through the iterators that determine which algorithms can
be applied to which types of objects. The STL relieves programmers from writing their
own implementations of various classes and functions. Instead, they can use prepack-
aged generic implementations accommodated to the problem at hand.

1.7.1 Containers
A container is a data structure that holds some objects that are usually of the same type.
Different types of containers organize the objects within them differently. Although
the number of different organizations is theoretically unlimited, only a small number
of them have practical significance, and the most frequently used organizations are in-
corporated in the STL. The STL includes the following containers: deque, list, map,
­ ultimap, set, multiset, stack, queue, priority_queue, an­d vector.
m
The STL containers are implemented as template classes that include mem-
ber functions specifying what operations can be performed on the elements stored
in the data structure specified by the container or on the data structure itself. Some
operations can be found in all containers, although they may be implemented dif-
ferently. The member functions common to all containers include the default con-
structor, copy constructor, destructor, empty(), max_size(), size(), swap(),
operator=, and, except in priority_queue, six overloaded relational operator
functions ( operator<, etc.). Moreover, the member functions common to all
containers ­except stack, queue, and priority_queue include the functions be-
gin(), end(), rbegin(), rend(), erase(), and clear().

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Section 1.7 The Standard Template Library ■ 25

Elements stored in containers can be of any type, and they have to supply at least
a default constructor, a destructor, and an assignment operator. This is particularly
important for user-defined types. Some compilers may also require some relational
operators to be overloaded (at least operators == and <, but maybe != and > as well)
even though the program does not use them. Also, a copy constructor and the func-
tion operator = should be provided if data members are pointers because insertion
operations use a copy of an element being inserted, not the element itself.

1.7.2 Iterators
An iterator is an object used to reference an element stored in a container. Thus, it is
a generalization of the pointer. An iterator allows for accessing information included
in a container so that desired operations can be performed on these elements.
As a generalization of pointers, iterators retain the same dereferencing notation. For
example, *i is an element referenced by iterator i. Also, iterator arithmetic is similar to
pointer arithmetic, although all operations on iterators are not allowed in all containers.
No iterators are supported for the stack, queue, and ­priority_queue con-
tainers. Iterator operations for classes list, map, multimap, set, and multiset
are as follows (i1 and i2 are iterators, n is a number):
i1++, ++i1, i1--, --i1
i1 = i2
i1 == i2, i1 != i2
*i1

In addition to these operations, iterator operations for classes deque and


­ ector are as follows:
v

i1 < i2, i1 <= i2, i1 > i2, i1 >= i2


i1 + n, i1 - n
i1 += n, i1 -= n
i1[n]

1.7.3 Algorithms
The STL provides some 70 generic functions, called algorithms, that can be applied to
the STL containers and to arrays. A list of all the algorithms is in Appendix B. These
algorithms are implementing operations that are very frequently used in most pro-
grams, such as locating an element in a container, inserting an element into a sequence
of elements, removing an element from a sequence, modifying elements, comparing
elements, finding a value based on a sequence of elements, sorting the sequence of ele-
ments, and so on. Almost all STL algorithms use iterators to indicate the range of ele-
ments on which they operate. The first iterator references the first element of the range,
and the second iterator references an element after the last element of the range. There-
fore, it is assumed that it is always possible to reach the position indicated by the second
iterator by incrementing the first iterator. Here are some examples.
The call
random_shuffle(c.begin(), c.end());

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
26 ■ Chapter 1 Object-Oriented Programming Using C++

randomly reorders all the elements of the container c. The call


i3 = find(i1, i2, el);

returns an iterator indicating the position of element el in the range i1 up to, but
not including, i2. The call
n = count_if(i1, i2, oddNum);

counts with the algorithm count_if() the elements in the range indicated by itera-
tors i1 and i2 for which a one-argument user-defined Boolean function oddNum()
returns true.
Algorithms are functions that are in addition to the member functions provided
by containers. However, some algorithms are also defined as member functions to
provide better performance.

1.7.4 Function Objects


In C++, the function call operator () can be treated as any other operator; in particu-
lar, it can be overloaded. It can return any type and take any number of arguments, but
like the assignment operator, it can be overloaded only as a member function. Any ob-
ject that includes a definition of the function call operator is called a function object. A
function object is an object, but it behaves as though it were a function. When the func-
tion object is called, its arguments become the arguments of the function call operator.
Consider the example of finding the sum of numbers resulting from applying a
function f to integers in the interval [n, m]. An implementation sum() presented in Sec-
tion 1.4.5 relied on using a function pointer as an argument of function sum(). The same
can be accomplished by first defining a class that overloads the function call operator:
class classf {
public:
classf() {
}
double operator() (double x) {
return 2*x;
}
};
and defining
double sum2(classf f, int n, int m) {
double result = 0;
for (int i = n; i <= m; i++)
result += f(i);
return result;
}

which differs from sum() only in the first parameter, which is a function object, not
a function; otherwise, it is the same. The new function can now be called, as in
classf cf;
cout << sum2(cf,2,5) << endl;

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Section 1.7 The Standard Template Library ■ 27

or simply
cout << sum2(classf(),2,5) << endl;
The latter way of calling requires a definition of constructor classf() (even if it has
no body) to create an object of type classf() when sum2() is called.
The same can be accomplished without overloading the function call operator,
as exemplified in these two definitions:
class classf2 {
public:
classf2 () {
}
double run (double x) {
return 2*x;
}
};
double sum3 (classf2 f, int n, int m) {
double result = 0;
for (int i = n; i <= m; i++)
result += f.run(i);
return result;
}
and a call
cout << sum3(classf2(),2,5) << endl;
The STL relies very heavily on function objects. The mechanism of function
pointers is insufficient for built-in operators. How could we pass a unary minus to
sum() ? The syntax sum(-,2,5) is illegal. To circumvent the problem, the STL
­defines function objects for the common C++ operators in <functional> . For
­example, unary minus is defined as
template<class T>
struct negate : public unary_function<T,T> {
T operator()(const T& x) const {
return -x;
}
};
Now, after redefining function sum() so that it becomes a generic function:
template<class F>
double sum(F f, int n, int m) {
double result = 0;
for (int i = n; i <= m; i++)
result += f(i);
return result;
}
the function can also be called with the negate function object:
sum(negate<double>(),2,5).
Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
28 ■ Chapter 1 Object-Oriented Programming Using C++

1.8 Vectors in the Standard Template Library


The simplest STL container is the vector, which is a data structure with contiguous
blocks of memory just like an array. Because memory locations are contiguous, they
can be randomly accessed so that the access time of any element of the vector is con-
stant. Storage is managed automatically so that on an attempt to insert an element
into a full vector, a larger memory block is allocated for the vector, the vector ele-
ments are copied to the new block, and the old block is released. A vector is thus a
flexible array; that is, an array whose size can be dynamically changed.
Figure 1.3 alphabetically lists all the vector member functions. An application of
these functions is illustrated in Figure 1.4. The contents of affected vectors are shown
as comments on the line in which member functions are called. The contents of a
vector are output with the generic function printVector(), but in the program in
­Figure 1.4 only one call is shown.

Figure 1.3 An alphabetical list of member functions in the class vector.

Member Function Operation


void assign(iterator first, Remove all the elements in the vector and insert in it the
iterator last) elements from the range indicated by iterators first and
last.
void assign(size_type n, Remove all the elements in the vector and insert in it n
const T& el = T()) copies of el.
T& at(size_type n) Return the element in position n of the vector.
const T& at(size_type n) const Return the element in position n of the vector.
T& back() Return the last element of the vector.
const T& back() const Return the last element of the vector.
iterator begin() Return an iterator that references the first element of the vector.
const_iterator begin() const Return an iterator that references the first element of the vector.
size_type capacity() const Return the number of elements that can be stored in the vector.
void clear() Remove all the elements in the vector.
bool empty() const Return true if the vector includes no element and false
otherwise.
iterator end() Return an iterator that is past the last element of the vector.
const_iterator end() const Return a const iterator that is past the last element of the
vector.
iterator erase(iterator i) ­Remove the element referenced by iterator i and return an
iterator referencing the element after the one removed.

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Section 1.8 Vectors in the Standard Template Library ■ 29

Figure 1.3 (continued)

iterator erase(iterator first, Remove the elements in the range indicated by iterators
iterator last) first and last and return an iterator referencing the ele-

ment after the last one removed.
T& front() Return the first element of the vector.
const T& front() const Return the first element of the vector.
iterator insert(iterator i, Insert el before the element referenced by iterator i and
const T& el = T()) return iterator referencing the newly inserted element.
void insert(iterator i, Insert n copies of el before the element referenced by
size_type n, const T& el) iterator i.
void insert(iterator i, Insert elements from the range indicated by iterators
iterator first, iterator last) first and last before the element referenced by ­iterator i.

size_type max_size() const Return the maximum number of elements for the vector.
T& operator[] Subscript operator.
const T& operator[] const Subscript operator.
void pop_back() Remove the last element of the vector.
void push_back(const T& el) Insert el at the end of the vector.
reverse_iterator rbegin() Return an iterator that references the last element of the vector.
const_reverse_iterator rbegin() Return an iterator that references the last element of the
const vector.
reverse_iterator rend() Return an iterator that is before the first element of the vector.
const_reverse_iterator rend() Return an iterator that is before the first element of the
const vector.
void reserve(size_type n) Reserve enough room for the vector to hold n items if its
capacity is less than n.
void resize(size_type n, Make the vector able to hold n elements by adding n -
const T& el = T()) ize() more positions with element el or by discarding
s
over­flowing size() - n positions from the end of the
vector.
size_type size() const Return the number of elements in the vector.
void swap(vector<T>& v) Swap the content of the vector with the content of another
vector v.
vector() Construct an empty vector.
vector(size_type n, Construct a vector with n copies of el of type T (if el is
const T& el = T()) not provided, a default constructor T() is used).
vector(iterator first, Construct a vector with the elements from the range indi-
iterator last) cated by iterators first and last.
vector(const vector<T>& v) Copy constructor.

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
30 ■ Chapter 1 Object-Oriented Programming Using C++

Figure 1.4 A program demonstrating the operation of vector member functions.

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional> // greater<T>

using namespace std;

template<class T>
void printVector(char *s, const vector<T>& v) {
cout << s << " = (";
if (v.size() == 0) {
cout << ")\n";
return;
}
typename vector<T>::const_iterator i = v.begin();
for( ; i != v.end()–1; i++)
cout << *i << ' ';
cout << *i << ")\n";
}

bool f1(int n) {
return n < 4;
}

int main() {
int a[] = {1,2,3,4,5};
vector<int> v1; // v1 is empty, size = 0, capacity = 0
printVector("v1",v1);
for (int j = 1; j <= 5; j++)
v1.push_back(j); // v1 = (1 2 3 4 5), size = 5, capacity = 8
vector<int> v2(3,7); // v2 = (7 7 7)
vector<int> ::iterator i1 = v1.begin()+1;
vector<int> v3(i1,i1+2); // v3 = (2 3), size = 2, capacity = 2
vector<int> v4(v1); // v4 = (1 2 3 4 5), size = 5, capacity = 5
vector<int> v5(5); // v5 = (0 0 0 0 0)
v5[1] = v5.at(3) = 9;// v5 = (0 9 0 9 0)
v3.reserve(6); // v3 = (2 3), size = 2, capacity = 6
v4.resize(7); // v4 = (1 2 3 4 5 0 0), size = 7, capacity = 10
v4.resize(3); // v4 = (1 2 3), size = 3, capacity = 10
v4.clear(); // v4 is empty, size = 0, capacity = 10 (!)
v4.insert(v4.end(),v3[1]); // v4 = (3)
v4.insert(v4.end(),v3.at(1)); // v4 = (3 3)

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Section 1.8 Vectors in the Standard Template Library ■ 31

Figure 1.4 (continued)

v4.insert(v4.end(),2,4); // v4 = (3 3 4 4)
v4.insert(v4.end(),v1.begin()+1,v1.end()-1); // v4 = (3 3 4 4 2 3 4)
v4.erase(v4.end()-2); // v4 = (3 3 4 4 2 4)
v4.erase(v4.begin(), v4.begin()+4); // v4 = (2 4)
v4.assign(3,8); // v4 = (8 8 8)
v4.assign(a,a+3); // v4 = (1 2 3)
vector<int>::reverse_iterator i3 = v4.rbegin();
for ( ; i3 != v4.rend(); i3++)
cout << *i3 << ' '; // print: 3 2 1
cout << endl;

// algorithms

v5[0] = 3; // v5 = (3 9 0 9 0)
replace_if(v5.begin(),v5.end(),f1,7); // v5 = (7 9 7 9 7)
v5[0] = 3; v5[2] = v5[4] = 0; // v5 = (3 9 0 9 0)
replace(v5.begin(),v5.end(),0,7); // v5 = (3 9 7 9 7)
sort(v5.begin(),v5.end()); // v5 = (3 7 7 9 9)
sort(v5.begin(),v5.end(),greater<int> ()); // v5 = (9 9 7 7 3)
v5.front() = 2; // v5 = (2 9 7 7 3)
return 0;
}

To use the class vector, the program has to contain the include instruction
#include <vector>
The class vector has four constructors. The declaration
vector<int> v5(5);

uses the same constructor as declaration


vector<int> v2(3,7);

but for vector v5, the element with which it is filled is determined by the default inte-
ger constructor, which is zero.
Vector v1 is declared empty and then new elements are inserted with the
function push_back(). Adding a new element to the vector is usually fast unless
the vector is full and has to be copied to a new block. This situation occurs if the
size of the vector equals its capacity. But if the vector has some unused cells, it can
accommodate a new element immediately in constant time. The current values of
the parameters can be tested with the function size(), which returns the num-
ber of elements currently in the vector, and the function capacity() , which

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
32 ■ Chapter 1 Object-Oriented Programming Using C++

returns the number of available cells in the vector. If necessary, the capacity can
be changed with the function reserve(). For ­example, after executing
v3.reserve(6);

vector v3 = (2 3) retains the same elements and the same size = 2, but its capac-
ity changes from 2 to 6. The function reserve() affects only the capacity of the
vector, not its content. The function resize() affects contents and possibly the
capacity. For example, vector v4 = (1 2 3 4 5) of size = capacity = 5 changes after
execution of
v4.resize(7);

to v4 = (1 2 3 4 5 0 0), size = 7, capacity = 10, and after another call to resize(),


v4.resize(3);

to v4 = (1 2 3), size = 3, capacity = 10. These examples indicate that new space is al-
located for vectors, but it is not returned.
Note that there is no member function push_front(). This reflects the fact
that adding a new element in front of the vector is a complex operation because it
requires that all of the elements are moved by one position to make room for the
new element. It is thus a time-consuming operation and can be accomplished with
the function insert(). This is also a function that automatically allocates more
memory for the vector if necessary. Other functions that perform this task are the
constructors, the function reserve(), and operator=.
Vector elements can be accessed with the subscript notation used for arrays,
as in
v4[0] = n;

or with iterators with the dereferencing notation used for pointers, as in


vector<int>::iterator i4 = v4.begin();
*i4 = n;

Note that some member functions have T& return type (that is, a reference type).
For example, for an integer vector, the signature of member function front() is
int& front();

This means that, for example, front() can be used on both the left side and the
right side of the assignment operator:
v5.front() = 2;
v4[1] = v5.front();

All the STL algorithms can be applied to vectors. For example, the call
replace(v5.begin(),v5.end(),0,7);

replaces all 0s with 7s in vector v5 so that v5 = (3 9 0 9 0) turns into v5 = (3 9 7 9 7),


and the call
sort(v5.begin(),v5.end());

Copyright 2012 Cengage Learning. All Rights Reserved. May not be copied, scanned, or duplicated, in whole or in part. Due to electronic rights, some third party content may be suppressed from the eBook and/or eChapter(s).
Editorial review has deemed that any suppressed content does not materially affect the overall learning experience. Cengage Learning reserves the right to remove additional content at any time if subsequent rights restrictions require it.
Other documents randomly have
different content
there were any special objects or interests to which it was not to
extend; and whether the revenues of the government were to be
derived from imposts laid at pleasure upon imports or exports, or
both; whether they might be derived from excises on the
manufactures or produce of the country; whether its power of direct
taxation was to be exercised under further limitations than those
already agreed upon for the apportionment of direct taxes among
the States;—all these details were as yet entirely unsettled.
Two subjects, one of which might fall within a general commercial
power, and the other within a general power to raise revenues, had
already been incidentally alluded to, and both were likely to create
great embarrassment. General Pinckney had twice given notice that
South Carolina could not accede to the new Union proposed, if it
possessed a power to tax exports.[211] It had also become apparent,
in the discussions and arrangements respecting the apportionment
of representatives, that the possible encouragement of the slave-
trade, which might follow an admission of the blacks into the rule of
representation, was one great obstacle, in the view of the Northern
States, to such an admission; and at the same time, that it was very
doubtful whether all the Southern States would surrender to the
general government the power to prohibit that trade.[212] The
compromise which had already taken place on the subject of
representation had settled the principles on which that difficult
matter was to be arranged. But the power to increase the slave
populations by continued importation had not been agreed to be
surrendered; and unless some satisfactory and reasonable
adjustment could be made on this subject, there could be no
probability that the Constitution would be finally ratified by the
people of the Northern States.[213] It is necessary, therefore, to look
carefully at these two subjects, namely, the taxation of exports and
the prohibition of the slave-trade.
That a power to lay taxes or duties on exported products belongs to
every government possessing a general authority to select the
objects from which its revenues are to be derived, is a proposition
which admits of little doubt. It is not to be doubted, either, that it is
a power which may be attended with great benefit, not only for
purposes of revenue, but for the encouragement of manufactures;
and it is clear that it may often be used as a means of controlling
the commercial policy of other countries, when applied to articles
which they cannot produce, but which they must consume. A
government that is destitute of this power is not armed with the
most complete and effectual means for counteracting the regulations
of foreign countries that bear heavily upon the industrial pursuits of
its people, although it may have other and sufficient sources of
revenue; and therefore, until an unrestricted commercial intercourse
and a free exchange of commodities become the general policy of
the world, to deny to any government a power over the exported
products of its own country, is to place it at some disadvantage with
all commercial nations that possess the power to enhance the price
of commodities which they themselves produce.
But, on the other hand, the practice of taxing the products of a
country, as they pass out of its limits to enter into the consumption
of other nations, can be beneficially exercised only by a government
that can select and arrange the objects of such taxation so as to do
nearly equal justice to all its producing interests. If, for example, the
article of wine were produced only by a single province of France,
and all the other provinces produced no commodities sought for by
other nations, an export duty upon wine would fall wholly upon the
single province where it was produced, and would place its
production at an unequal competition with the wines of other
countries. But France produces a variety of wines, the growth of
many different provinces; and therefore, in the adjustment of an
export duty upon wines, the government of that country, after a due
regard to the demand for each kind or class of this commodity, has
chiefly to consider the effect of such a tax in the competition with
the same commodity produced by other nations.
At the time of the formation of the Constitution of the United States,
there was not a single production, common to all the States, of
sufficient importance to become an article of general exportation.
Indeed, there were no commodities produced for exportation by so
many of the States, that a tax or duty imposed upon them on
leaving the country would operate with anything like equality even in
different sections of the Union. In fact, from the extreme northern to
the extreme southern boundary of the Union, the exports were so
various, both in kind and amount, that a tax imposed on an article
the produce of the South could not be balanced by a tax imposed
upon an article produced or manufactured at the North. How, for
example, could the burden of an export duty on the tobacco of
Virginia, or the rice or indigo of South Carolina, be equalized by a
similar duty on the lumber or fish or flour of other States? Possibly,
after long experience and the accumulation of the necessary
statistics, an approach towards an equality of such burdens might
have been made; but it could never have become more than an
unsatisfactory approximation; and while the effect of such a tax at
one end of the Union on the demand for the commodity subjected to
it might be estimated,—because the opportunity for other nations to
supply themselves elsewhere might be so precise as to be easily
measured,—its effect at the other end of the Union, on another
commodity, might be wholly uncertain, because the demand from
abroad might be influenced by new sources of supply, or might from
accidental causes continue to be nearly the same as before.
However theoretically correct it might have been, therefore, to
confer on the general government the same authority to tax exports
as to impose duties on imported commodities,—and the argument
for it drawn from the necessities for revenue and protection of
manufactures was exceedingly strong,—the actual situation of the
country made it quite impracticable to obtain the consent of some of
the States to a full and complete revenue power. Several of the most
important persons in the Convention were strongly in favor of it.
Washington, Madison, Wilson, Gouverneur Morris, and Dickinson are
known to have held the opinion, that the government would be
incomplete, without a power to tax exports as well as imports. But
the decided stand taken by South Carolina, whose exports for a
single year were said by General Pinckney to have amounted to
£600,000, the fruit of the labor of her slaves, probably led the
committee of detail to insert in their report of a draft of the
Constitution a distinct prohibition against laying any tax or duty on
articles exported from any State.
A similar question, in relation to the extent of the commercial power,
was destined to arise out of the relations of the different States to
the slave-trade. If the power to regulate commerce, that might be
conferred upon the general government, was to be universal and
unlimited, it must include the right to prohibit the importation of
slaves. If the right to sanction or tolerate the importation of slaves,
which, like all other political rights, belonged to the people of the
several States as sovereign communities, was to be retained by
them as an exception from the commercial power which they might
confer upon the national legislature, that exception must be clearly
and definitely established. For several reasons, the question was
necessarily to be met, as soon as the character and extent of the
commercial power should come into discussion. While the trade had
been prohibited by all the other States, including Virginia and
Maryland, it had only been subjected to a duty by North Carolina,
and was subjected to a similar discouragement by South Carolina
and Georgia. The basis of representation in the national legislature,
in which it had been agreed that the slaves should be included in a
certain ratio, created a strong political motive with the Northern
States to obtain for the general government a power to prevent
further importations. It was fortunate that this motive existed; for
the honor and reputation of the country were concerned to put an
end to this traffic. No other nation, it was true, had at that time
abolished it; but here were the assembled States of America,
engaged in framing a Constitution of government, that ought, if the
American character was to be consistent with the principles of the
American Revolution, to go as far in the recognition of human rights
as the circumstances of their actual situation would admit. What was
practicable to be done, from considerations of humanity, and all that
could be successfully done, was the measure of their duty as
statesmen, admitted and acted upon by the framers of the
Constitution, including many of those who represented slaveholding
constituencies, as well as the representatives of States that had
either abolished both the traffic in slaves and the institution itself, or
were obviously destined to do it.
This just and necessary rule of action, however, which limited their
efforts to what the actual circumstances of the country would
permit, made a clear distinction between a prohibition of the future
importation of slaves, and the manumission of those already in the
country. The former could be accomplished, if the consent of the
people of the States could be obtained, without trenching on their
sovereign control over the condition of all persons within their
respective limits. It involved only the surrender of a right to add to
the numbers of their slaves by continued importations. But the
power to determine whether the slaves then within their limits
should remain in that condition, could not be surrendered by the
people of the States, without overturning every principle on which
the system of the new government had been rested, and which had
thus far been justly regarded as essential to its establishment and to
its future successful operation.
It is not, therefore, to be inferred, because a large majority of the
Convention sought for a power to prohibit the increase of slaves by
further importation, that they intended by means of it to extinguish
the institution of slavery within the States. So far as they acted from
a political motive, they designed to take away the power of a State
to increase its congressional representation by bringing slaves from
Africa; and so far as they acted from motives of general justice and
humanity, they designed to terminate a traffic which never has been
and never can be carried on without infinite cruelty and national
dishonor. That the individuals of an inferior race already placed in
the condition of servitude to a superior one may, by the force of
necessity, be rightfully left in the care and dominion of those on
whom they have been cast, is a proposition of morals entirely fit to
be admitted by a Christian statesman. That new individuals may
rightfully be placed in the same condition, not by the act of
Providence through the natural increase of the species, but by the
act of man in transferring them from distant lands, is quite another
proposition. The distinction between the two, so far as a moral
judgment is concerned with the acts of the framers of the
Constitution upon the circumstances before them, defines the limits
of duty which they intended to recognize.
No satisfactory means exist for determining to what extent a
continuance of the importation of slaves was necessary, in an
economical point of view, to the States of North Carolina, South
Carolina, and Georgia. There is some reason to suppose that the
natural increase of the slave population in Virginia at that period
more than supplied her wants; and perhaps the less healthy regions
of the more southern States may have still required foreign supplies
in order to keep the lands already occupied under cultivation, or to
make new lands productive.[214] All that is historically certain on this
subject is, that the representatives of the three most southerly
States acted upon the belief, that their constituents would not
surrender the right to continue the importation of slaves, although
they might, if left to themselves, discontinue the practice at some
future time.
These declarations, however, had not been made at the time when
the principles on which the Constitution was to be framed were sent
to the committee of detail. Nothing had yet occurred in the
Convention, to make it certain that the power to import would be
retained by any of the States. The committee of detail had,
therefore, so far as the action of the Convention had gone, an
unrestricted choice between a full and a limited commercial power.
They consisted of three members from non-slaveholding and two
from slaveholding States;[215] but as one of them, Mr. Rutledge of
South Carolina, was one of the persons who subsequently
announced to the Convention the position that would be taken by his
own State and by North Carolina and Georgia, there can be no doubt
that he announced the same determination in the committee. In
their report, they shaped the commercial power accordingly. They
provided that the legislature of the United States should have power
to lay and collect taxes, duties, imposts, and excises; and to regulate
commerce with foreign nations, and among the several States.
But they also reported several restrictions upon both the revenue
and commercial powers. Besides providing, in accordance with the
ninth resolution adopted by the Convention, that direct taxation
should be proportioned among the States according to the census,
to be taken by a particular rule, they added the further restrictions,
that no tax or duty should be laid by the national legislature on
articles exported from any State, nor on the migration or importation
of such persons as the several States might think proper to admit;
that such migration or importation should not be prohibited; that no
capitation tax should be laid, unless in proportion to the census; and
that no navigation act should be passed without the assent of two
thirds of the members present in each house.
That the new government must have a direct revenue power, was
generally conceded, and it was also generally admitted that it must
have a power to regulate commerce with foreign countries. But the
idea was more or less prevalent among the Southern statesmen,
that the interest of their own States, considered as a distinct and
separate interest from that of the commercial States, did not require
a regulation of commerce by the general government. It is not easy
to determine to what extent these views were correct. Taking into
consideration nothing more than the fact, that the staple production
of Virginia was tobacco, as it was also partly that of North Carolina;
that rice and indigo were the great products of South Carolina and
Georgia; and that neither of these four States possessed a large
amount of shipping;—it might certainly be considered that an
unrestricted foreign intercourse was important to them.
But, on the other hand, if those States, by clothing the Union with a
power to regulate commerce, were likely to subject themselves to a
temporary rise of freights, the measures which might have that
effect would also tend directly to increase Southern as well as
Northern shipping, to augment the commercial marine of the whole
country, and thus to increase its general maritime strength. The
general security thus promoted was as important to one class of
States as to another. The increase of the coasting trade would also
increase the consumption of the produce of all the States. The great
benefit, however, to be derived from a national regulation of
commerce,—a benefit in which all the States would equally share,
whatever might be their productions,—was undoubtedly the removal
of the existing and injurious retaliations which the States had
hitherto practised against each other.[216]
Still, these advantages were indirect or incidental. The immediate
and palpable commercial interests of different portions of the Union,
regarded in the mass, were not identical; and it was in one sense
true, that the power of regulating commerce was a concession on
the part of the Southern States to the Northern, for which they
might reasonably expect equivalent advantages, or which they might
reasonably desire to qualify by some restriction.
On the reception of the report of the committee of detail, and when
the article relating to representation was reached, the consequences
of agreeing that the slaves should be computed in the rule, taken in
connection with an unrestrained power in the States to increase the
slave populations by further importation, and with the exemption of
exports from taxation, became more prominent, and more likely to
produce serious dissatisfaction. The concession of the slave
representation had been made by some of the Northern members, in
the hope that it might be the means of strengthening the plan of
government, and of procuring for it full powers both of revenue and
of commercial regulation. But now, it appeared that, as to two very
important points, the hands of the national legislature were to be
absolutely tied. The importation of slaves could not be prohibited;
exports could not be taxed. These restrictions seemed to many to
have an inevitable tendency to defeat the great primary purposes of
a national government. All must agree, that defence against foreign
invasion and against internal sedition was one of the principal
objects for which such a government was to be established. Were all
the States then to be bound to defend each, and was each to be at
liberty to introduce a weakness which would increase both its own
and the general danger, and at the same time to withhold the
compensation for the burden? If slaves were to be imported, why
should not the exports produced by their labor supply a revenue,
that would enable the general government to defend their masters?
To refuse it, was so inequitable and unreasonable, said Rufus King,
that he could not assent to the representation of the slaves, unless
exports should be taxable;—perhaps he could not finally consent to
it, under any circumstances.[217]
Gouverneur Morris, with his accustomed ardor, went further still, and
insisted on re-opening the subject of representation, now that the
other features of the system were to be made to favor the increase
of slaves, and to throw the burdens of maintaining the government
chiefly upon the Northern States. It was idle, he declared, to say
that direct taxation might be levied upon the slaveholding States in
proportion to their representative population: for the general
government could never stretch out its hand, and put it directly into
the pockets of the people, over so vast a country. Its revenues must
be derived from exports, imports, and excises. He therefore would
not consent to the sacrifices demanded, and moved the insertion of
the word "free" before the word "inhabitants," in the article
regulating the basis of representation.[218]
But there were few men in the Convention bold enough to hazard
the consequences of unsettling an arrangement, which had cost so
much labor and anxiety; which had been made as nearly correct in
theory as the circumstances of the case would allow; and which was,
in truth, the best practical solution of a great difficulty. Mr. Morris's
motion received the vote of a single State only.[219] The great
majority of the delegations considered it wiser to go on to the
discussion of the proposed restrictions upon the revenue and
commercial powers, in the hope that each of them might be
considered and acted upon with reference to the true principles
applicable to the subject, or that the whole might be adjusted by
some agreement that would not disturb what had been settled with
so much difficulty.
The great embarrassment attending the proposed restriction upon
the taxation of exports was, that, however the question might be
decided, it would probably lose for the new government the support
of some important members of the Convention. Those who regarded
it as right that the government should have a complete revenue
power, contended for the convenience with which a large staple
production, in which America was not rivalled in foreign markets,
could be made the subject of an export tax, that would in reality be
paid by the foreign consumer. On the other side, the very facility
with which such objects could be selected for taxation alarmed the
States whose products presented the best opportunity for exercising
this power. They did not deny the obvious truth, that the tax must
ultimately fall on the consumer; but they considered it enough to
surrender the power of levying duties upon imports, without giving
up the control which each State now had over its own productions.
[220]

But there was also another question involved in the form in which
the proposed restriction had been presented. It prohibited the
national government from taxing exports, but imposed no restraint
in this respect upon the power of the States. If they were to retain
the power over their own exports, they would have the same right to
tax the products of other States exported through their maritime
towns. This power had been used to a great extent, and always
oppressively. Virginia had taxed the tobacco of North Carolina;
Pennsylvania had taxed the products of Maryland, of New Jersey,
and of Delaware; and it was apparent, that every State, not
possessed of convenient and accessible seaports, must hereafter
submit to the same exactions, if this power were left unrestrained.
Give it to the general government, said the advocates for a full
revenue power, and the inconveniences attending its exercise by the
separate States will be avoided. But those who were opposed to the
possession of such a power by the general government,
apprehended greater oppression by a majority of the States acting
through the national legislature, than they could suffer at the hands
of individual States. The eight Northern States, they said, had an
interest different from the five Southern States, and in one branch of
the legislature the former were to have thirty-six votes, and the
latter twenty-nine.
From considerations like these, united with others which would
render it nearly impracticable to select the objects of such taxation
so as to make it operate equally, the restriction prevailed.[221] The
revenue power was thus shorn of one great branch of taxation,
which, however difficult it might be to practise it throughout such a
country as this, is part of the prerogatives of every complete
government, which was believed by many to be essential to the
success of the proposed Constitution, but which was resisted
successfully by others, as oppressive to their local and peculiar
interests.
Was the commercial power to experience a like diminution from the
full proportions of a just authority over the external trade of the
States? Were the States, whose great homogeneous products,
derived from the labor of slaves, would supply no revenue to the
national treasury, to be left at liberty to import all the slaves that
Africa could furnish? Were the commercial States to see the carrying
trade of the country—embracing the very exports thus exempted
from burdens of every kind, and thus stimulated by new accessions
of slaves—pass into foreign bottoms, and be unable to protect their
interests by a majority of votes in the national legislature? Was there
to be no advantageous commercial treaty obtained from any foreign
power, unless the measures needful to compel it could gain the
assent of two thirds of Congress? Was the North to be shut out for
ever from the West India trade, and was it at the same time to see
the traffic in slaves prosecuted without restraint, and without the
prospect or the hope of a final termination?
These were grave and searching questions. The vote exempting
exports from the revenue power could not be recalled. It had passed
by a decided majority of the States; and many suffrages had been
given for the exemption, not from motives of a sectional nature, but
on account of the difficulty that must attend the exercise of the
power, and from the conviction that such taxation is incorrect in
principle. So far, therefore, the Southern States had gained all that
they desired in respect to the revenue power, and now three of
them, with great firmness, declared that the question in relation to
the commercial power was, whether they should or should not be
parties to the Union. If required to surrender their right to import
slaves, North Carolina, South Carolina, and Georgia would not accept
the Constitution, although they were willing to make slaves liable to
an equal tax with other imports.[222] It was also manifest, that the
clause which required a navigation act to be passed by two thirds of
each house, was to be insisted on by some, although not by all, of
the Southern members.
Thus was a dark and gloomy prospect a second time presented to
the framers of the Constitution. If, on the one side, there were
States feeling themselves bound as a class to insist on certain
concessions, on the other side were those by whom such
concessions could not be made. The chief motive with the Eastern,
and with most of the Northern States, in seeking a new union under
a new frame of government, was a commercial one. They had
suffered so severely from the effects of the commercial policy of
England and other European nations, and from the incapacity of
Congress to control that policy, that it had become indispensable to
them to secure a national power which could dictate the terms and
vehicles of commercial intercourse with the whole country. Cut off
from the British West India trade by the English Orders in Council,
the Eastern and Middle States required other means of counteracting
those oppressive regulations than could be found in their separate
State legislation, which furnished no power whatever for obtaining a
single commercial treaty.[223] Besides these considerations, which
related to the special interests of the commercial States, the want of
a navy, which could only be built up by measures that would
encourage the growth of the mercantile marine, and which, although
needed for the protection of commerce, was also required for the
defence of the whole country, made it necessary that the power to
pass a navigation act should be burdened with no serious
restrictions.
The idea of requiring a vote of two thirds in Congress for the
passage of a navigation act, founded on the assumed diversity of
Northern and Southern, or the commercial and the planting
interests, proceeded upon the necessity for a distinct protection of
the latter against the former, by means of a special legislative check.
To a certain extent, as I have already said, these interests, when
regarded in their aggregates, offered a real diversity. But it did not
follow that this peculiar check upon the power of a majority was
either a necessary or an expedient mode of providing against
oppressive legislation. In every system of popular government, there
are great disadvantages in departing from the simple rule of a
majority; and perhaps the principle which requires the assent of
more than a majority ought never to be extended to mere matters of
legislation, but should be confined to treaty stipulations, and to
those fundamental changes which affect the nature of the
government and involve the terms on which the different portions of
society are associated together.
It was undoubtedly the purpose of those who sought for this
particular restriction, to qualify the nature of the government, in its
relation to the interests of commerce. But the real question was,
whether there existed any necessary reason for placing those
interests upon a different footing from that of all other subjects of
national legislation. The operation of the old rule of the
Confederation, which required the assent of nine States in Congress
to almost all the important measures of government, many of which
involved no fundamental right of separate States, had revealed the
inconveniences of lodging in the hands of a minority the power to
obstruct just and necessary legislation. If, indeed, it was highly
probable that the power, by being left with a majority, would be
abused,—if the interests of the Eastern and Middle States were
purely and wholly commercial, and would be likely so to shape the
legislation of the country as to encourage the growth of its
mercantile marine, at the expense of other forms of industry and
enterprise, and no other suitable and efficient checks could be
found,—then the restriction proposed might be proper and
necessary.
But in truth the separate interests of the Eastern and Middle States,
when closely viewed, were not in all respects the same. Connecticut
and New Jersey were agricultural States. New York and
Pennsylvania, although interested in maritime commerce, were
destined to be great producers of the most important grains.
Maryland, although a commercial, was also an agricultural State. The
new States likely to be formed in the West would be almost wholly
agricultural, and would have no more shipping than might be
required to move the surplus products of their soil upon their great
inland lakes towards the shores of the Atlantic. All these States,
existing and expectant, were interested to obtain commercial
treaties with foreign countries; all needed the benefits of uniform
commercial regulations; but they were not all equally interested in a
high degree of encouragement to the growth of American shipping,
by means of a stringent navigation act, that would bear heavily upon
the Southern planter.
Not only was there a very considerable protection against the abuse
of its power by a sectional majority, in these more minute diversities
of interest, but there were also two very efficient legislative checks
upon that power already introduced into the government. If an
unjust and oppressive measure had commanded a majority in the
House, it might be defeated in the Senate, or, if that check should
fail, it might be arrested by the executive.
It had, nevertheless, been made part of the limitations upon the
commercial power, embraced in the report of the committee of
detail, that a navigation act should require a vote of two thirds of
both branches of the legislature. The vote which adopted the
prohibition against taxes on exports, taken on the 21st of August,
was followed, on that day and the next, by an excited debate on the
taxation of the slave-trade, in which the three States of Georgia,
North Carolina, and South Carolina made the limitation upon the
power of the Union over this traffic the condition of their accepting
the Constitution. This debate was closed by the proposition of
Gouverneur Morris, to refer the whole subject to a committee of one
from each State, in order that the three matters of exports, the
slave-trade, and a navigation act might form a bargain or
compromise between the Northern and the Southern States.[224] But
the prohibition against taxing exports had already been agreed to,
and there remained to be committed only the proposed restriction
against taxing or prohibiting the migration or importation of such
persons as the States might see fit to admit, the restriction which
required a capitation tax to conform to the census, and the proposed
limitation upon the power to pass a navigation act. Thus, in effect,
the questions to come before this committee were, whether the
slave-trade should be excepted from both the commercial and
revenue powers of the general government, and whether the
commercial power should be subjected to a restriction which
required a vote of two thirds in dealing with the commercial interests
of the Union.
We know very little of the deliberations of this committee; but as
each State was equally represented in it, and as the position of the
different sectional objects is quite clear, we can have no difficulty in
forming an opinion as to the motives and purposes of the settlement
which resulted from their action, or in obtaining a right estimate of
the result itself.
In the first place, then, we are to remember the previous
concessions already made by the Northern States, and the
advantages resulting from them. These concessions were the
representation of the slaves and the exemption of exports from
taxation. If the slaves had not been included in the system of
representation, the Northern States could have had no political
motive for acquiring the power to put an end to the slave-trade. If
the exports of their staple productions had not been withdrawn from
the revenue power, the Southern States could have had no very
strong or special motive to draw them into the new Union; but with
such an exemption, they could derive benefits from the Constitution
as great as those likely to be enjoyed by their Northern
confederates. Both parties, therefore, entered the final committee of
compromise with a strong desire to complete the Union and to
establish the new government. The Northern States wished for a full
commercial power, including the slave-trade and navigation laws, to
be dependent on the voices of a majority in Congress. The Southern
States struggled to retain the right to import slaves, and to limit the
enactment of navigation laws to a vote of two thirds. Both parties
could be gratified only by conceding some portion of their respective
demands.
If the Northern States could accept a future, instead of an
immediate, prohibition of the slave-trade, they could gain ultimately
a full commercial power over all subjects, to be exercised by a
national majority. If the Southern States could confide in a national
majority, so far as to clothe them with full ultimate power to regulate
commerce, they could obtain the continuance of the slave-trade for
a limited period.
Such was in reality the adjustment made and recommended by the
committee. They proposed that the migration or importation of such
persons as the several States then existing might think proper to
admit, should not be prohibited by the national legislature before the
year 1800, but that a tax or duty might be imposed on such persons,
at a rate not exceeding the average of the duties laid on imports;
that the clause relating to a capitation tax should remain; and that
the provision requiring a navigation act to be passed by a vote of
two thirds, should be stricken out.[225]
No change was made in this arrangement, when it came before the
Convention, except to substitute the year 1808 as the period at
which the restriction on the commercial power was to terminate, and
to provide for a specific tax on the importation of slaves, not
exceeding ten dollars on each person.[226] The remaining features of
this settlement, relating to a capitation tax and a navigation act,
were sanctioned by a large majority of the States.[227]
Thus, by timely and well-considered concessions on each side, was
the slave-trade brought immediately within the revenue power of the
general government, and also, at the expiration of twenty years,
within its power to regulate commerce. By the same means, the
commercial power, without any other restriction than that relating to
the temporary toleration of the importation of slaves, was vested in
a national majority. This result at once placed the foreign slave-trade
by American vessels or citizens within the control of the national
legislature, and enabled Congress to forbid the carrying of slaves to
foreign countries; and at the end of the year 1808, it brought the
whole traffic within the reach of a national prohibition.[228]
Too high an estimate cannot well be formed, of the importance and
value of this final settlement of conflicting sectional interests and
demands. History has to thank the patriotism and liberality of the
Northern States, for having acquired, for the government of the
Union, by reasonable concessions, the power to terminate the
African slave-trade. We know, from almost every day's experience
since the founding of the government, that individual cupidity, which
knows no geographical limits, which defies public opinion whether in
the North or in the South, required and still requires the restraint
and chastisement of national power. The separate authority of the
States would have been wholly unequal to the suppression of the
slave-trade: for even if they had all finally adopted the policy of a
stringent prohibition, without a navy, and without treaties, they
could never have contended against the bold artifice and desperate
cunning of avarice, stimulated by the enormous gains which have
always been reaped in this inhuman trade.
The just and candid voice of History has also to thank the Southern
statesmen who consented to this arrangement, for having clothed a
majority of the two houses of Congress with a full commercial power.
They felt, and truly felt, that this was a great concession. But they
looked at what they had gained. They had gained the exemption of
their staple productions from taxation as objects of foreign
commerce; the enumeration of their slaves in the basis of
Congressional representation; and the settlement of the slave-trade
upon terms not offensive to State pride. They had also gained the
Union, with its power to maintain an army and a navy,—with its
power and duty to protect them against foreign invasion and
domestic insurrection, and to secure their republican constitutions.
They looked, therefore, upon the grant of the power to regulate
commerce by the ordinary modes of legislation, in its relations to the
interests of a great empire, whose foundations ought to be laid
broadly and deeply on the national welfare.[229] They saw that the
Revolution had cost the Eastern States enormous sacrifices of
commercial wealth, and that the weakness of the Confederation had
destroyed the little remnant of their trade.[230] They saw and
admitted the necessity for an unrestrained control over the foreign
commerce of the country, if it was ever to rise from the prostrate
condition in which it had been placed by foreign powers. They acted
accordingly; and by their action, they enabled the States of North
Carolina, South Carolina, and Georgia to enter the new Union
without humiliation and without loss.[231]
Thus was accomplished, so far as depended on the action of this
Convention, that memorable compromise, which gave to the Union
its control over the commercial relations of the States with foreign
nations and with each other. An event so fraught with consequences
of the utmost importance cannot be dismissed without some of the
reflections appropriate to its consideration.
Nature had marked America for a great commercial nation. The
sweep of the Atlantic coast, from the Bay of Fundy to the Gulf of
Florida, comprehending twenty degrees of latitude, broken into
capacious bays and convenient harbors, and receiving the inward
flow of the sea into great navigable rivers that stretched far into the
interior, presented an access to the ocean not surpassed by that of
any large portion of the globe. This long range of sea-coast
embraced all the varieties of climate that are found between a hard
and sterile region, where summer is but the breath of a few fervid
weeks, and the ever blooming tropics, where winter is unknown. The
products of the different regions, already entering, or fit to enter,
into foreign commerce, attested as great a variety of soils. The
proximity of the country to the West Indies, where the Eastern and
the Middle States could find the best markets for some of their most
important exports, afforded the promise of a highly lucrative trade;
while the voyage to the East Indies from any American port could be
performed in as short a time as from England or Holland or France.
In the South, there were great staples already largely demanded by
the consumption of Europe. In the North, there were fisheries of
singular importance, capable of furnishing enormous additions to the
wealth of the country. Beyond the Alleghanies, the West, with its
vast internal waters and its almost unequalled fertility, had been
opened to a rapid emigration, which was soon to lay the foundation
of new States, destined to be the abodes of millions of men.
The very variety and extent of these interests had for many years
occasioned a struggle for some mode of reconciling and harmonizing
them all. But divided into separate governments, the commercial
legislation of the States could produce nothing but the confusion and
uncertainty which retaliation necessarily engenders. Different
systems and rates of revenue were in force in seaports not a
hundred miles apart, through which the inhabitants of other
jurisdictions were obliged to draw their supplies of foreign
commodities, and to export their own productions. The paper-money
systems of the several States made the commercial value of coin
quite different in different places, and gave an entirely insecure basis
to trade.
The reader, who has followed me through the preceding volume, has
seen how the people of the United States, from the earliest stages of
the Revolution, struggled to free themselves from these
embarrassments;—how they commenced with a jealous reservation
of State authority over all matters of commerce and revenue; how
they undertook to supply the necessities of a central government by
contributions which they had not the power to make good, because
their commercial condition did not admit of heavy taxation; how they
endeavored to pass from this system to a grant of temporary
revenues and temporary commercial regulation, to be vested in the
federal Union; how they found it impracticable to agree upon the
principles and details of a temporary power; how they turned to
separate commercial leagues, each with its immediate neighbors,
and were disappointed in the result or frustrated in the effort; and
how at last they came to the conception of a full and irrevocable
surrender of commercial and fiscal regulations to a central
legislature, that could grasp the interests of the whole country and
combine them in one harmonious system.
The influence of the commercial and revenue powers, thus obtained
by the general government, on the condition of this country, has far
exceeded the most sanguine hopes which the framers of the
Constitution could have indulged. No one can doubt that the people
of America owe to it both the nature and the degree of their actual
prosperity;—and as the national prosperity has given them
importance in the world, it is just and accurate to say, that
commerce and its effects have elevated republican institutions to a
dignity and influence which they have attained through no other of
the forms or the spirit of society. Let the reader consider the
interests of commerce, in their widest relations with all that they
comprehend,—the interests of the merchant, the artisan, and the
tiller of the soil being alike involved,—as the chief purpose of the
new government given to this Union; let him contemplate this as the
central object around which are arranged almost all the great
provisions of the Constitution of the United States;—and he will see
in it a wonderfully harmonious and powerful system, created for the
security of property, and the promotion of the material welfare and
prosperity of individuals, whatever their occupation, employment, or
condition. That such a code of civil government should have sprung
from the necessities of commerce, is surely one of the triumphs of
modern civilization.
It is not to be denied, that the sedulous care with which this great
provision was made for the general prosperity has had the effect of
impressing on the national character a strong spirit of acquisition.
The character of a people, however, is to be judged not merely by
the pursuit or the possession of wealth, but chiefly by the use which
they make of it. If the inhabitants of the United States can justly
claim distinction for the benevolent virtues; if the wealth that is
eagerly sought and rapidly acquired is freely used for the relief of
human suffering; if learning, science, and the arts are duly
cultivated; if popular education is an object of lavish expenditure; if
the institutions of religion, though depending on a purely voluntary
support, are provided for liberally, and from conscientious motives;—
then is the national spirit of acquisition not without fruits, of which it
has no need to be ashamed.
The objection, that the Constitution of the United States, and the
immense prosperity which has flowed from it, were obtained by
certain concessions in favor of the institution of slavery, results from
a merely superficial view of the subject. If we would form a right
estimate of the gain or loss to human nature effected by any given
political arrangement, we must take into consideration the
antecedent facts, and endeavor to judge whether a better result
could have been obtained by a different mode of dealing with them.
We shall then be able to appreciate the positive good that has been
gained, or the positive loss that has been suffered.
The prominent facts to be considered in this connection are, in the
first place, that slavery existed, and would long exist, in certain of
the States; and that the condition of the African race in those States
was universally regarded as a matter of purely local concern. It could
not in fact have been otherwise; for there were slaves in every State
excepting Massachusetts and New Hampshire; and among the other
States in which measures had been, or were likely to be, taken for
the removal of slavery, there was a great variety of circumstances
affecting the time and mode in which it should be finally
extinguished. As soon as the point was settled, in the formation of
the Constitution of the United States, that the State governments
were to be preserved, with all their powers unimpaired which were
not required by the objects of the national government to be
surrendered to the Union, the domestic relations of their inhabitants
with each other necessarily remained under their exclusive control.
Those relations were not involved in the purposes of the Federal
Union.
So soon, also, as this was perceived and admitted, it became a
necessary consequence of the admission, that the national authority
should guarantee to the people of each State the right to shape and
modify their own social institutions; for without this principle laid at
the foundation of the Union, there could be no peace or security for
such a mixed system of government.
In the second place, we have to consider the fact, that, among the
political rights of the States anterior to the national Constitution, was
the right to admit or to prohibit the further importation of slaves;—a
traffic not then forbidden by any European nation to its Colonies, but
which had been interdicted by ten of the American States. The
transfer of this right to the Federal Union was a purely voluntary act;
it was not strictly necessary for the purposes for which it was
proposed to establish the Constitution of the United States; although
there were political reasons for which a part of the States might wish
to acquire control over this subject, as well as moral reasons why all
the States should have desired to vest that control in the general
government. Three of the States, however, as we have seen, took a
different view of their interest and duty, and declined to enter the
new Union unless this traffic should be excepted from the power
over commerce for a period of twenty years.
It is quite plain, that, if these facts had been met and dealt with in a
manner different from the settlement that was actually made, one of
two consequences must have ensued;—either no Constitution at all
could have been adopted, or there would have been a Union of
some kind, from which three at least of the States must have been
excluded. If the first, by far the most probable contingency, had
happened, a great feebleness and poverty of society must have
continued to be the lot of all these States; there must have been
perpetual collisions and rival confederacies; there certainly would
have been an indefinite continuance of the slave-trade, accompanied
and followed by a great external pressure upon the States which
permitted it, which would have led to a war of races, or to a frightful
oppression of the slaves. Most of these evils would have followed the
establishment of a partial confederacy.
On the other hand, we are to consider what has been gained to
humanity by the establishment of the Constitution. The extinction of
the slave-trade, followed by a public opinion with reference to it that
is as strong and reliable in the Southern as in the Northern States,
was purchased at a price by no means unreasonable, when
compared with the magnitude of the acquisition. The great
prosperity and high civilization which are due to the commercial
power of the Constitution have been a vast benefit to both races;—
to the whites by the superior refinement they have created, and to
the blacks by the gradual but certain amelioration of their condition.
The social strength and security occasioned by constantly increasing
wealth, combined with the acknowledgment and establishment of
the doctrine which makes every State the uncontrolled arbiter of the
domestic condition of its inhabitants, has put it in the power of those
who have charge of the negro to deal prudently and wisely with their
great problem, without the interference of those who could benefit
neither race by their intervention. This, in every rational view of the
subject, cannot but be regarded as one of the chief blessings
conferred by the Constitution of the United States.
It has made emancipation possible, where otherwise it would have
been impossible, or where it could have been obtained only through
the horrors of both servile and civil war. It has enabled local
authorities to adapt changes to local circumstances. Its beneficent
influences may be traced in the laws of the States, in the records of
their jurisprudence, and in the advanced and advancing condition of
their public sentiment; and he who should follow those influences in
all their details, and count the sum of what it has effected for the
moral and physical well-being of the subjected race, would find
cause for devout gratitude to the Ruler of the Universe. Great as has
been the increase of slaves in the United States during the last
seventy years, there can be no question that the general
improvement of their condition has been equally great, and that it
has kept pace with the increasing prosperity of the country. That
prosperity has enabled individual enterprise and benevolence to
plant a colony upon the coast of Africa, which, after centuries of
discipline and education, may yet be the means of restoring to its
native soil, as civilized and Christian men, a race that came to us as
heathens and barbarians.
Surely, then, with such results to look back upon, with such hopes in
the future, the patriot and the Christian can have no real cause for
regret or complaint, that in a system of representative government,
made necessary by controlling circumstances, the unimportant
anomaly should be found, of a representation of men without
political rights or social privileges; or that the question of
emancipation, either for the mass or the individual, should be
carefully secured to local authority; or even that the slave-trade
should have been prosecuted for a few years, to be extinguished by
America first of all the nations of the world.
CHAPTER XI.
Report of the Committee of Detail, Continued.—The Remaining Powers
of Congress.—Restraints Upon Congress and Upon the States.

In the last preceding chapter, the reader has traced the origin of the
revenue and commercial powers, and of certain restrictions applied
to them in the progress of those great compacts, by means of which
they became incorporated into the Constitution. We have now to
examine some other qualifications which were annexed to those
powers after the first draft of the instrument had been prepared and
reported by the committee of detail.
That committee had presented a naked power to lay and collect
taxes, duties, imposts, and excises,[232] with a certain restriction as
to the taxation of exports, the final disposition of which has been
already described; but they had designated no particular objects to
which the revenues thus derived were to be applied. The general
clause embracing the revenue power was affirmed unanimously by
the Convention, on the 16th of August, leaving the exception of
exports for future action. At a subsequent period we find the words,
"to pay the debts and provide for the common defence and general
welfare of the United States," added to the clause which empowers
Congress to levy taxes and duties; and it is a somewhat important
inquiry, how and with what purpose they were placed there.
While the powers proposed by the committee of detail were under
consideration, Mr. Charles Pinckney introduced several topics
designed to supply omissions in their report, which were thereupon
referred to that committee. The purpose of one of his suggestions
was to provide, on the one hand, that funds appropriated for the
payment of public creditors should not, during the time of such
appropriation, be diverted to any other purpose; and, on the other
hand, that Congress should be restrained from establishing
perpetual revenues. Another of his suggestions contemplated a
power to secure the payment of the public debt, and still another to
prevent a violation of the public faith when once pledged to any
public creditor.[233] Immediately after this reference, Mr. Rutledge
moved for what was called a grand committee,[234] to consider the
expediency of an assumption by the United States of the State
debts; and after some discussion of the subject, such a committee
was raised, and Mr. Rutledge's motion was referred to them,
together with a proposition introduced by Mr. Mason for restraining
grants of perpetual revenue.[235] Thus it appears that the principal
subject involved in the latter reference was the propriety of inserting
in the Constitution a specific power to make special appropriations
for the payment of debts of the United States and of the several
States, incurred during the late war for the common defence and
general welfare; and not to make a declaration of the general
purposes for which revenues were to be raised. Both committees,
however, seemed to have been charged with the consideration of
some restraint on the revenue power, with a view to prevent
perpetual taxes of any kind. The grand committee reported first,
presenting the following special provision:—"The legislature of the
United States shall have power to fulfil the engagements which have
been entered into by Congress, and to discharge, as well the debts
of the United States, as the debts incurred by the several States
during the late war for the common defence and general welfare."
[236] On the following day, the committee of detail presented a
report, recommending that at the end of the clause already adopted,
which contained the grant of the revenue power, the following words
should be added: "for payment of the debts and necessary expenses
of the United States; provided that no law for raising any branch of
revenue, except what may be specially appropriated for the payment
of interest on debts or loans, shall continue in force for more than
—— years."[237]
Two distinct propositions were thus before the Convention. One of
them contemplated a qualification of the revenue power, the other
did not. One was to give authority to Congress to pay the
revolutionary debt, both of the United States and of the States, and
to fulfil all the engagements of the Confederation; the other was to
declare that revenues were to be raised and taxes levied for the
purpose of paying the debts and necessary expenses of the United
States, limiting all revenue laws, excepting those which were to
appropriate specific funds to the payment of interest on debts or
loans, to a term of years. When these propositions came to be acted
upon, that reported by the grand committee was modified into the
declaration that "all debts contracted and engagements entered into,
by or under the authority of Congress, shall be as valid against the
United States, under this Constitution, as under the Confederation."
The State debts were thus left out; the declaration was prefixed, as
an amendment, to the clause which granted the revenue power, and
was thus obviously no qualification of that power.[238]
But it was thought by Mr. Sherman, that the clause for laying taxes
and duties ought to have connected with it an express provision for
the payment of the old debts; and he accordingly moved to add to
that clause the words, "for the payment of said debts, and for the
defraying the expenses that shall be incurred for the common
defence and general welfare." This was regarded by the Convention
as unnecessary, and was therefore not adopted.[239] But the
provision reported by the committee of detail, which was intended
as a qualification of the revenue power, by declaring the objects for
which taxes and duties were to be levied, had not yet been acted
upon, and on the 31st of August, this, with all other matters not
disposed of, was referred to a new grand committee, who, on the
4th of September, introduced an amendment to the revenue clause,
which made it read as follows:—"The legislature shall have power to
lay and collect taxes, duties, imposts, and excises, to pay the debts,
and provide for the common defence and general welfare of the
United States." This amendment was unanimously adopted;[240] and
when the Constitution was revised, at the close of the proceedings,
the declaration which made the debts and engagements of the
Confederation obligatory upon the new Congress, was separated
from the context of the revenue clause, and placed by itself in the
sixth article.
There is one other restraint upon the revenue, as well as upon the
commercial power, the history of which now demands our inquiries.
But in order to understand it correctly, it will be necessary for the
reader to recur to the position in which the revenue and commercial
powers were left by the sectional compromises described in the last
chapter. The struggle between the Northern and the Southern States
concerning the limitations of those powers turned, as we have seen,
on certain restrictions desired by the latter. They wished to have
exports excepted out of the revenue power; they wished to have a
vote of two thirds made necessary to the passage of any commercial
regulation; and three of them wished to have the slave-trade
excepted from both the revenue and the commercial powers. We
have seen that the result of the sectional compromises was to leave
the commercial and revenue powers unlimited, excepting by the
saving in relation to the slave-trade; that they left the revenue
power unlimited, excepting by the restriction concerning exports and
a capitation tax; and that the commercial power was to be
exercised, like other legislative powers, by a majority in Congress.
General commercial and revenue powers, then, without other
restrictions than these, would enable Congress to collect their
revenues where they should see fit, without obliging them to adopt
the old ports of entry of the States, or to consider the place where a
cargo was to be unladen. They might have custom-houses in only
one place in each State, or in only such States as they might choose
to select, and might thus compel vessels bound from or to all the
other States to clear or enter at those places. But, on the other
hand, a constitutional provision which would require them to
establish custom-houses at the old ports of entry of the States,
without leaving them at liberty to establish other ports of entry, or to
compel vessels to receive on board revenue officers before they had
Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade

Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.

Let us accompany you on the journey of exploring knowledge and


personal growth!

ebookball.com

You might also like