about
CvsC++
12/17/2022

C and C++ Language Comparison

"[In Unix] We have persistant objects, they're called files."
- Ken Thompson

Synopsis:

C++ is based on a C language core. Most C programs will compile as C++ programs. C++ adds:

  • C++ references
  • Function overloading
  • classes
  • Scope-based resource management
  • Inheritance
  • templates
  • I/O Streams
  • template containers
Inheritance and templates allow us to build very flexible code that is easy to reuse and that gracefully accomodates changes in requirements. That only happens if you use good design practices.

These are excellent references for the C++ language:

Similarities between C and C++

  • Most C programs will compile as C++ programs.
  • They share the same compilation model.
  • Both generate native code and allow programs to directly manage resources.
  • Both can use platform APIs by consuming platfrom header files and linking to platform libraries.
  • Both have scopes that are compile-time only artifacts and other scopes that have run-time behavior:
    • Compile-time scopes:
      • C struct and enum scopes.
      • C++ namespace, class/struct, and enum scopes
    • Both C and C++ have the same Run-time scopes:
      • Function, looping, selection, and anonymous scopes
      • Entering a run-time scope causes a stack frame1 to be allocated to hold local data, e.g., scratch-pad memory.
      • When the thread of execution leaves a scope its stack frame becomes invalid. The next time a scope is entered that memory may be reallocated to the new scope.
  • C++ can use the Standard C library (but usually doesn't need to).
  • Both are relatively strongly typed; both allow escaping the type system with casts.
  • Both have the same primitive types, use static arrays and structs, and have string libraries.
  • C and C++ structs support composition (hold another struct) and aggregation (hold a pointer to another struct)
  • Both use the same pointer syntax.
  • They share the same memory models.

Differences between C and C++

  • Programs written in C++ include system libraries without the .h extension, e.g., #include<iostream>. The C Language libraries are still available. Instead of using #include <stdio.h> use #include <cstdio>.
  • C++ adds references to the type system.
    • C++ references wrap pointers. The wrapper provides the same object syntax as the type referenced.
    • Unlike pointers, C++ references must be bound at declaration and cannot be reset to refer to a different object.
  • C functions pass and return by value. C++ functions pass and return by both value and reference.
    • C and C++ functions can both pass and return pointers, but C++ references provide simpler syntax in many contexts.
  • C++ functions can be overloaded. Overloaded functions share the same name, but must have a different sequence of parameter types.
    • To support function overloading the compiler uses mangled names which consist of the name and parameter sequence in tokenized form. It is the mangled name that gets bound to a code block for execution.
    • Overloading is essential for C++ classes, as we will see below.
  • C++ introduces classes.
    • C++ classes have both data and function members.
    • classes provide access control, e.g., public, protected, and private access.
    • class instances can be declared in static memory, stack memory, or on the heap, using new and delete.
    • C++ structs are identical to C++ classes except for their default access levels - public for structs, private for classes.
  • C++ classes have an elegant resource management process:
    • Member functions that have the same name as their class are constructors, responsible for initializing a newly created instance.
    • C++ supports default construction, parameterized construction, copy construction, and move construction. We will discuss all of these when we look at the anatomy of classes in the next slide.
    • Any function with name the same as the class but prepended with a tilde (~) is a destructor.
    • when a class instance is declared in some scope the instance is intialized at the point of declaration and destroyed, by calling the destructor, when the thread of execution leaves that scope.
    • This means that, for correctly defined classes, code using a class does not have to participate in any way with resource allocation and deallocation for any locally defined instances of that class. That all happens automatically.
  • C++ classes can support either value type or reference type behavior.
    • Value types can be copied, so the copy appears to have the same state as the original instance, even if instances of the class hold pointers to resources on the native heap. C++ provides facilities for building copy constructors that manage copy operations and support overloading of assignment operations to correctly manage assignment of the heap resources. Note that managed code languages like Java and C# do not provide means to do that.
    • Reference types hold pointers to resources on the heap, but copying and assignment just copy and assign the references, not the resources they refer to. C++ supports building reference types by using std::unique_ptr to transfer ownership for copy and assignment operations. It also provides std::shared_ptr to share ownership of a resource using reference counting, so the resource is not deallocated until all references go out of scope or are set to nullptr.
    • Note that when we use the term reference type here, we are not talking about the C++ reference wrapper, but rather a class that manages some resource with an internal pointer and does not copy or assign the state of that resource. In a sense a reference type is a generalization of the C++ reference.
  • C++ classes support Inheritance2 and may have virtual functions which are dispatched at run-time via Virtual Function Pointer Tables (vtbl).
  • C++ uses the new and delete operators for memory management. A call to new allocates memory on the native heap, and is guaranteed to initialize the allocation with a constructor call. Invoking delete on an instance in the heap calls it's destructor to return resourses to the system.
  • Inheritance supports:
    • code sharing - all derived classes share the same non-virtual function implementations.
    • specializing derived types by overriding virtual member functions.
    • substitution:
      Any function that accepts a base class pointer or reference will accept a pointer or reference to a class derived from that base.
    • Parser example
  • C++ provides template syntax to support generic programming. We can, in library code, implement classes and functions that depend on a parameter not specified until an application instantiates the template. The C++ containers are all defined with template classes.
  • Error handling can use exceptions, using the key words try, catch, and throw. Exceptions enable handling errors without constantly checking returned error codes.
  • The standard C++ library provides:
We will see examples of all of these C++ language artifacts in the code examples to follow.

C++ Philosophy:

  • Provide mechanics for strong encapsulation - only member functions of classes can access private data managed by the class. That means that a well-designed class can make strong guarantees about the integrity of its managed data.
  • Attempt to pay for features at compile-time rather than run-time, e.g., no built-in index bounds checking, no garbage collection, and no built-in error handling. Note, however, if you want those features it is relatively easy to provide them for your classes, either by using library facilities or rolling your own.
  • In the spirit of C, prefer to enable developers rather than protect them.

  1. A stack frame is an allocation of stack memory provided by the process to a scope about to become active, e.g., the thread of execution is about to enter the scope. This allocation is valid only as long as the thread of execution is in that scope.
  2. C++ does not have an interface construct. However, a struct with:
    • no data members
    • no constructors
    • all pure virtual methods, except for a non-pure virtual destructor with empty body
    is semantically equivalent to the interface contracts in C# and Java. This "interface" serves to declare a contract for service provided by all classes that have this struct as a base, e.g., implement the interface.
  Next Prev Pages Sections About Keys