Saturday, 4 July 2015

concept of file system in c..


                           file system




in computing a file system   (or filesystem) is used to control how data is stored and retrieved. Without a file system, information placed in a storage area would be one large body of data with no way to tell where one piece of information stops and the next begins. By separating the data into individual pieces, and giving each piece a name, the information is easily separated and identified. Taking its name from the way paper-based information systems are named, each group of data is called a "file". The structure and logic rules used to manage the groups of information and their names is called a "file system".

There are many different kinds of file systems. Each one has different structure and logic, properties of speed, flexibility, security, size and more. Some file systems have been designed to be used for specific applications. For example, the ISO 9660 file system is designed specifically for optical discs.

File systems can be used on many different kinds of storage devices. Each storage device uses a different kind of media. The most common storage device in use today is a hard drive whose media is a disc that has been coated with a magnetic film. The film has ones and zeros 'written' on it sending electrical pulses to a magnetic "read-write" head. Other media that are used are magnetic tape, optical disc, and flash memory. In some cases, the computer's main memory (RAM) is used to create a temporary file system for short term use.

Some file systems are used on local data storage devices;[1] others provide file access via a network protocol (for example, NFS,[2] SMB, or 9P clients). Some file systems are "virtual", in that the "files" supplied are computed on request (e.g. procfs) or are merely a mapping into a different file system used as a backing store. The file system manages access to both the content of files and the metadata about those files. It is responsible for arranging storage space; reliability, efficiency, and tuning with regard to the physical storage medium are important design considerations.


                               Space management



Note: this only applies to file systems used in storage devices.
Example of slack space, demonstrated with 4,096-byte NTFS clusters: 100,000 files, each 5 bytes per file, equals 500,000 bytes of actual data, but requires 409,600,000 bytes of disk space to store
File systems allocate space in a granular manner, usually multiple physical units on the device. The file system is responsible for organizing files and directories, and keeping track of which areas of the media belong to which file and which are not being used. For example, in Apple DOS of the early 1980s, 256-byte sectors on 140 kilobyte floppy disk used a track/sector map.[citation needed]

This results in unused space when a file is not an exact multiple of the allocation unit, sometimes referred to as slack space. For a 512-byte allocation, the average unused space is 256 bytes. For 64 KB clusters, the average unused space is 32 KB. The size of the allocation unit is chosen when the file system is created. Choosing the allocation size based on the average size of the files expected to be in the file system can minimize the amount of unusable space. Frequently the default allocation may provide reasonable usage. Choosing an allocation size that is too small results in excessive overhead if the file system will contain mostly very large files.

File system fragmentation occurs when unused space or single files are not contiguous. As a file system is used, files are created, modified and deleted. When a file is created the file system allocates space for the data. Some file systems permit or require specifying an initial space allocation and subsequent incremental allocations as the file grows. As files are deleted the space they were allocated eventually is considered available for use by other files. This creates alternating used and unused areas of various sizes. This is free space fragmentation. When a file is created and there is not an area of contiguous space available for its initial allocation the space must be assigned in fragments. When a file is modified such that it becomes larger it may exceed the space initially allocated to it, another allocation must be assigned elsewhere and the file becomes fragmented.

Filenames 


Main article: Filename

A filename (or file name) is used to identify a storage location in the file system. Most file systems have restrictions on the length of filenames. In some file systems, filenames are not case sensitive (i.e., filenames such as FOO and foo refer to the same file); in others, filenames are case sensitive (i.e., the names FOO, Foo and foo refer to three separate files).

Most modern file systems allow filenames to contain a wide range of characters from the Unicode character set. However, they may have restrictions on the use of certain special characters, disallowing them within filenames; those characters might be used to indicate a device, device type, directory prefix, file path separator, or file type.

Directories

Main article: Directory (file systems)
File systems typically have directories (also called folders) which allow the user to group files into separate collections. This may be implemented by associating the file name with an index in a table of contents or an inode in a Unix-like file system. Directory structures may be flat (i.e. linear), or allow hierarchies where directories may contain subdirectories. The first file system to support arbitrary hierarchies of directories was used in the Multics operating system.[3] The native file systems of Unix-like systems also support arbitrary directory hierarchies, as do, for example, Apple's Hierarchical File System, and its successor HFS+ in classic Mac OS (HFS+ is still used in Mac OS X), the FAT file system in MS-DOS 2.0 and later and Microsoft Windows, the NTFS file system in the Windows NT family of operating systems, and the ODS-2 (On-Disk Structure-2) and higher levels of the Files-11 file system in OpenVMS.

Metadata

Other bookkeeping information is typically associated with each file within a file system. The length of the data contained in a file may be stored as the number of blocks allocated for the file or as a byte count. The time that the file was last modified may be stored as the file's timestamp. File systems might store the file creation time, the time it was last accessed, the time the file's metadata was changed, or the time the file was last backed up. Other information can include the file's device type (e.g. block, character, socket, subdirectory, etc.), its owner user ID and group ID, its access permissions and other file attributes (e.g. whether the file is read-only, executable, etc.).

A file system stores all the metadata associated with the file—including the file name, the length of the contents of a file, and the location of the file in the folder hierarchy—separate from the contents of the file.

Most file systems store the names of all the files in one directory in one place—the directory table for that directory—which is often stored like any other file. Many file systems put only some of the metadata for a file in the directory table, and the rest of the metadata for that file in a completely separate structure, such as the inode.

Most file systems also store metadata not associated with any one particular file. Such metadata includes information about unused regions—free space bitmap, block availability map—and information about bad sectors. Often such information about an allocation group is stored inside the allocation group itself.

Additional attributes can be associated on file systems, such as NTFS, XFS, ext2, ext3, some versions of UFS, and HFS+, using extended file attributes. Some file systems provide for user defined attributes such as the author of the document, the character encoding of a document or the size of an image.

Some file systems allow for different data collections to be associated with one file name. These separate collections may be referred to as streams or forks. Apple has long used a forked file system on the Macintosh, and Microsoft supports streams in NTFS. Some file systems maintain multiple past revisions of a file under a single file name; the filename by itself retrieves the most recent version, while prior saved version can be accessed using a special naming convention such as "filename;4" or "filename(-4)" to access the version four saves ago.

See comparison of file systems#Metadata for details on which file systems support which kinds of metadata.

File system as an abstract user interface

In some cases, a file system may not make use of a storage device but can be used to organize and represent access to any data, whether it is stored or dynamically generated (e.g. procfs).

Utilities

The difference between a utility and a built-in core command function is arbitrary, depending on the design of the operating system, and on the memory and space limitations of the hardware. For example, Microsoft MS-DOS uses a utility for formatting and a built-in command for simple file copying, while in the Apple DOS formatting is a built-in command and simple file copying is performed by using a utility.

File systems include utilities to initialize, alter parameters of and remove an instance of the file system. Some include the ability to extend or truncate the space allocated to the file system.

Directory utilities may be used to create, rename and delete directory entries, which are also known as dentries (singular: dentry),[4] and to alter metadata associated with a directory. Directory utilities may also include capabilities to create additional links to a directory (hard links in Unix), to rename parent links (".." in Unix-like operating systems),[clarification needed] and to create bidirectional links to files.

File utilities create, list, copy, move and delete files, and alter metadata. They may be able to truncate data, truncate or extend space allocation, append to, move, and modify files in-place. Depending on the underlying structure of the file system, they may provide a mechanism to prepend to, or truncate from, the beginning of a file, insert entries into the middle of a file or delete entries from a file.

Utilities to free space for deleted files, if the file system provides an undelete function, also belong to this category.

Some file systems defer operations such as reorganization of free space, secure erasing of free space, and rebuilding of hierarchical structures by providing utilities to perform these functions at times of minimal activity. Included in this category is the infamous defragmentation utility.[which?]

Some of the most important features of file system utilities involve supervisory activities which may involve bypassing ownership or direct access to the underlying device. These include high-performance backup and recovery, data replication and reorganization of various data structures and allocation tables within the file system.

Restricting and permitting access

See also: Computer security, Password cracking, Filesystem-level encryption and Encrypting File System
There are several mechanisms used by file systems to control access to data. Usually the intent is to prevent reading or modifying files by a user or group of users. Another reason is to ensure data is modified in a controlled way so access may be restricted to a specific program. Examples include passwords stored in the metadata of the file or elsewhere and file permissions in the form of permission bits, access control lists, or capabilities. The need for file system utilities to be able to access the data at the media level to reorganize the structures and provide efficient backup usually means that these are only effective for polite users but are not effective against intruders.

Methods for encrypting file data are sometimes included in the file system. This is very effective since there is no need for file system utilities to know the encryption seed to effectively manage the data. The risks of relying on encryption include the fact that an attacker can copy the data and use brute force to decrypt the data. Losing the seed means losing the data.

Maintaining integrity

One significant responsibility of a file system is to ensure that, regardless of the actions by programs accessing the data, the structure remains consistent. This includes actions taken if a program modifying data terminates abnormally or neglects to inform the file system that it has completed its activities. This may include updating the metadata, the directory entry and handling any data that was buffered but not yet updated on the physical storage media.

Other failures which the file system must deal with include media failures or loss of connection to remote systems.

In the event of an operating system failure or "soft" power failure, special routines in the file system must be invoked similar to when an individual program fails.

The file system must also be able to correct damaged structures. These may occur as a result of an operating system failure for which the OS was unable to notify the file system, power failure or reset.

The file system must also record events to allow analysis of systemic issues as well as problems with specific files or directories.

User data

The most important purpose of a file system is to manage user data. This includes storing, retrieving and updating data.

Some file systems accept data for storage as a stream of bytes which are collected and stored in a manner efficient for the media. When a program retrieves the data it specifies the size of a memory buffer and the file system transfers data from the media to the buffer. Sometimes a runtime library routine may allow the user program to define a record based on a library call specifying a length. When the user program reads the data the library retrieves data via the file system and returns a record.

Some file systems allow the specification of a fixed record length which is used for all write and reads. This facilitates updating records.

An identification for each record, also known as a key, makes for a more sophisticated file system. The user program can read, write and update records without regard to their location. This requires complicated management of blocks of media usually separating key blocks and data blocks. Very efficient algorithms can be developed with pyramid structure for locating records.[citation needed]

Using a file system

Utilities, language specific run-time libraries and user programs use file system APIs to make requests of the file system. These include data transfer, positioning, updating metadata, managing directories, managing access specifications, and removal.

Multiple file systems within a single system

Frequently retail systems are configured with a single file system occupying the entire hard disk.

Another approach is to partition the disk so that several file systems with different attributes can be used. One file system, for use as browser cache, might be configured with a small allocation size. This has the additional advantage of keeping the frantic activity of creating and deleting files typical of browser activity in a narrow area of the disk and not interfering with allocations of other files. A similar partition might be created for email. Another partition, and file system might be created for the storage of audio or video files with a relatively large allocation. One of the file systems may normally be set read-only and only periodically be set writable.

A third approach, which is mostly used in cloud systems, is to use "disk images" to house additional file systems, with the same attributes or not, within another (host) file system as a file. A common example is virtualization: one user can run an experimental Linux distribution (using the ext4 file system) in a virtual machine under his/her production Windows environment (using NTFS). The ext4 file system resides in a disk image, which is treated as a file (or multiple files, depending on the hypervisor and settings) in the NTFS host file system.

Having multiple file systems on a single system has the additional benefit that in the event of a corruption of a single partition, the remaining file systems will frequently still be intact. This includes virus destruction of the system partition or even a system that will not boot. File system utilities which require dedicated access can be effectively completed piecemeal. In addition, defragmentation may be more effective. Several system maintenance utilities, such as virus scans and backups, can also be processed in segments. For example it is not necessary to backup the file system containing videos along with all the other files if none have been added since the last backup. As for the image files, one can easily "spin off" differential images which contain only "new" data written to the master (original) image. Differential images can be used for both safety concerns (as a "disposable" system - can be quickly restored if destroyed or contaminated by a virus, as the old image can be removed and a new image can be created in matter of seconds, even without automated procedures) and quick virtual machine deployment (since the differential images can be quickly spawned using a script in batches).

Design limitations


All file systems have some functional limit that defines the maximum storable data capacity within that system. These functional limits are a best-guess effort by the designer based on how large the storage systems are right now and how large storage systems are likely to become in the future. Disk storage has continued to increase at near exponential rates (see Moore's law), so after a few years, file systems have kept reaching design limitations that require computer users to repeatedly move to a newer system with ever-greater capacity.

File system complexity typically varies proportionally with the available storage capacity. The file systems of early 1980s home computers with 50 KB to 512 KB of storage would not be a reasonable choice for modern storage systems with hundreds of gigabytes of capacity. Likewise, modern file systems would not be a reasonable choice for these early systems, since the complexity of modern file system structures would quickly consume or even exceed the very limited capacity of the early storage systems.

Types of file systems

File system types can be classified into disk/tape file systems, network file systems and special-purpose file systems.

Disk file systems


A disk file system takes advantages of the ability of disk storage media to randomly address data in a short amount of time. Additional considerations include the speed of accessing data following that initially requested and the anticipation that the following data may also be requested. This permits multiple users (or processes) access to various data on the disk without regard to the sequential location of the data. Examples include FAT (FAT12, FAT16, FAT32), exFAT, NTFS, HFS and HFS+, HPFS, UFS, ext2, ext3, ext4, XFS, btrfs, ISO 9660, Files-11, Veritas File System, VMFS, ZFS, ReiserFS and UDF. Some disk file systems are journaling file systems or versioning file systems.

Optical discs

ISO 9660 and Universal Disk Format (UDF) are two common formats that target Compact Discs, DVDs and Blu-ray discs. Mount Rainier is an extension to UDF supported since 2.6 series of the Linux kernel and since Windows Vista that facilitates rewriting to DVDs.

Flash file systems

Main article: Flash file system
A flash file system considers the special abilities, performance and restrictions of flash memory devices. Frequently a disk file system can use a flash memory device as the underlying storage media but it is much better to use a file system specifically designed for a flash device.

Tape file systems

A tape file system is a file system and tape format designed to store files on tape in a self-describing form. Magnetic tapes are sequential storage media with significantly longer random data access times than disks, posing challenges to the creation and efficient management of a general-purpose file system.

In a disk file system there is typically a master file directory, and a map of used and free data regions. Any file additions, changes, or removals require updating the directory and the used/free maps. Random access to data regions is measured in milliseconds so this system works well for disks.

Tape requires linear motion to wind and unwind potentially very long reels of media. This tape motion may take several seconds to several minutes to move the read/write head from one end of the tape to the other.

Consequently, a master file directory and usage map can be extremely slow and inefficient with tape. Writing typically involves reading the block usage map to find free blocks for writing, updating the usage map and directory to add the data, and then advancing the tape to write the data in the correct spot. Each additional file write requires updating the map and directory and writing the data, which may take several seconds to occur for each file.

Tape file systems instead typically allow for the file directory to be spread across the tape intermixed with the data, referred to as streaming, so that time-consuming and repeated tape motions are not required to write new data.

However, a side effect of this design is that reading the file directory of a tape usually requires scanning the entire tape to read all the scattered directory entries. Most data archiving software that works with tape storage will store a local copy of the tape catalog on a disk file system, so that adding files to a tape can be done quickly without having to rescan the tape media. The local tape catalog copy is usually discarded if not used for a specified period of time, at which point the tape must be re-scanned if it is to be used in the future.

IBM has developed a file system for tape called the Linear Tape File System. The IBM implementation of this file system has been released as the open-source IBM Linear Tape File System — Single Drive Edition (LTFS-SDE) product. The Linear Tape File System uses a separate partition on the tape to record the index meta-data, thereby avoiding the problems associated with scattering directory entries across the entire tape.

Tape formatting

Writing data to a tape is often a significantly time-consuming process that may take several hours. Similarly, completely erasing or formatting a tape can also take several hours. With many data tape technologies it is not necessary to format the tape before over-writing new data to the tape. This is due to the inherently destructive nature of overwriting data on sequential media.

Because of the time it can take to format a tape, typically tapes are pre-formatted so that the tape user does not need to spend time preparing each new tape for use. All that is usually necessary is to write an identifying media label to the tape before use, and even this can be automatically written by software when a new tape is used for the first time.

Database file systems

Another concept for file management is the idea of a database-based file system. Instead of, or in addition to, hierarchical structured management, files are identified by their characteristics, like type of file, topic, author, or similar rich metadata.

IBM DB2 for i [6] (formerly known as DB2/400 and DB2 for i5/OS) is a database file system as part of the object based IBM i  operating system (formerly known as OS/400 and i5/OS), incorporating a single level store and running on IBM Power Systems (formerly known as AS/400 and iSeries), designed by Frank G. Soltis IBM's former chief scientist for IBM i. Around 1978 to 1988 Frank G. Soltis and his team at IBM Rochester have successfully designed and applied technologies like the database file system where others like Microsoft later failed to accomplish.These technologies are informally known as 'Fortress Rochester'[citation needed] and were in few basic aspects extended from early Mainframe technologies but in many ways more advanced from a technological perspective

Some other projects that aren't "pure" database file systems but that use some aspects of a database file system:

Many Web content management systems use a relational DBMS to store and retrieve files. For example, XHTML files are stored as XML or text fields, while image files are stored as blob fields; SQL SELECT (with optional XPath) statements retrieve the files, and allow the use of a sophisticated logic and more rich information associations than "usual file systems". Many CMSs also have the option of storing only metadata within the database, with the standard filesystem used to store the content of files.
Very large file systems, embodied by applications like Apache Hadoop and Google File System, use some database file system concepts.

Transactional file systems

Some programs need to update multiple files "all at once". For example, a software installation may write program binaries, libraries, and configuration files. If the software installation fails, the program may be unusable. If the iinstallation is upgrading a key system utility, such as the command shell, the entire system may be left in an unusable state.

Transaction processing introduces the isolation guarantee, which states that operations within a transaction are hidden from other threads on the system until the transaction commits, and that interfering operations on the system will be properly serialized with the transaction. Transactions also provide the atomicity guarantee, ensuring that operations inside of a transaction are either all committed or the transaction can be aborted and the system discards all of its partial results. This means that if there is a crash or power failure, after recovery, the stored state will be consistent. Either the software will be completely installed or the failed installation will be completely rolled back, but an unusable partial install will not be left on the system.

Windows, beginning with Vista, added transaction support to NTFS, in a feature called Transactional NTFS, but its use is now discouraged.[9] There are a number of research prototypes of transactional file systems for UNIX systems, including the Valor file system,[10] Amino,[11] LFS,[12] and a transactional ext3 file system on the TxOS kernel,[13] as well as transactional file systems targeting embedded systems, such as TFFS.[14]

Ensuring consistency across multiple file system operations is difficult, if not impossible, without file system transactions. File locking can be used as a concurrency control mechanism for individual files, but it typically does not protect the directory structure or file metadata. For instance, file locking cannot prevent TOCTTOU race conditions on symbolic links. File locking also cannot automatically roll back a failed operation, such as a software upgrade; this requires atomicity.

Journaling file systems are one technique used to introduce transaction-level consistency to file system structures. Journal transactions are not exposed to programs as part of the OS API; they are only used internally to ensure consistency at the granularity of a single system call.

Data backup systems typically do not provide support for direct backup of data stored in a transactional manner, which makes recovery of reliable and consistent data sets difficult. Most backup software simply notes what files have changed since a certain time, regardless of the transactional state shared across multiple files in the overall dataset. As a workaround, some database systems simply produce an archived state file containing all data up to that point, and the backup software only backs that up and does not interact directly with the active transactional databases at all. Recovery requires separate recreation of the database from the state file, after the file has been restored by the backup software.

Network file systems

Main article: Distributed file system
A network file system is a file system that acts as a client for a remote file access protocol, providing access to files on a server. Programs using local interfaces can transparently create, manage and access hierarchical directories and files in remote network-connected computers. Examples of network file systems include clients for the NFS, AFS, SMB protocols, and file-system-like clients for FTP and WebDAV.

Shared disk file systems

Main article: Shared disk file system
A shared disk file system is one in which a number of machines (usually servers) all have access to the same external disk subsystem (usually a SAN). The file system arbitrates access to that subsystem, preventing write collisions. Examples include GFS2 from Red Hat, GPFS from IBM, SFS from DataPlow, CXFS from SGI and StorNext from Quantum Corporation.

Special file systems 

A special file system presents non-file elements of an operating system as files so they can be acted on using file system APIs. This is most commonly done in Unix-like operating systems, but devices are given file names in some non-Unix-like operating systems as well.

Device file systems 

A device file system represents I/O devices and pseudo-devices as files, called device files. Examples in Unix-like systems include devfs and, in Linux 2.6 systems, udev. In non-Unix-like systems, such as TOPS-10 and other operating systems influenced by it, where the full filename or pathname of a file can include a device prefix, devices other than those containing file systems are referred to by a device prefix specifying the device, without anything following it.

Other special file systems

In the Linux kernel, configfs and sysfs provide files that can be used to query the kernel for information and configure entities in the kernel.
procfs maps processes and, on Linux, other operating system structures into a filespace.
Minimal file system / audio-cassette storage[edit]
The late 1970s saw the development of the microcomputer. Disk and digital tape devices were too expensive for hobbyists. An inexpensive basic data storage system was devised that used common audio cassette tape.

When the system needed to write data, the user was notified to press "RECORD" on the cassette recorder, then press "RETURN" on the keyboard to notify the system that the cassette recorder was recording. The system wrote a sound to provide time synchronization, then modulated sounds that encoded a prefix, the data, a checksum and a suffix. When the system needed to read data, the user was instructed to press "PLAY" on the cassette recorder. The system would listen to the sounds on the tape waiting until a burst of sound could be recognized as the synchronization. The system would then interpret subsequent sounds as data. When the data read was complete, the system would notify the user to press "STOP" on the cassette recorder. It was primitive, but it worked (a lot of the time). Data was stored sequentially, usually in an unnamed format, although some systems (such as the Commodore PET series of computers) did allow the files to be named. Multiple sets of data could be written and located by fast-forwarding the tape and observing at the tape counter to find the approximate start of the next data region on the tape. The user might have to listen to the sounds to find the right spot to begin playing the next data region. Some implementations even included audible sounds interspersed with the data.

Flat file systems


In a flat file system, there are no subdirectories.

When floppy disk media was first available this type of file system was adequate due to the relatively small amount of data space available. CP/M machines featured a flat file system, where files could be assigned to one of 16 user areas and generic file operations narrowed to work on one instead of defaulting to work on all of them. These user areas were no more than special attributes associated with the files, that is, it was not necessary to define specific quota for each of these areas and files could be added to groups for as long as there was still free storage space on the disk. The early Apple Macintosh also featured a flat file system, the Macintosh File System. It was unusual in that the file management program (Macintosh Finder) created the illusion of a partially hierarchical filing system on top of EMFS. This structure required every file to have a unique name, even if it appeared to be in a separate folder.

While simple, flat file systems become awkward as the number of files grows and makes it difficult to organize data into related groups of files.

A recent addition to the flat file system family is Amazon's S3, a remote storage service, which is intentionally simplistic to allow users the ability to customize how their data is stored. The only constructs are buckets (imagine a disk drive of unlimited size) and objects (similar, but not identical to the standard concept of a file). Advanced file management is allowed by being able to use nearly any character (including '/') in the object's name, and the ability to select subsets of the bucket's content based on identical prefixes.

File systems and operating systems

Many operating systems include support for more than one file system. Sometimes the OS and the file system are so tightly interwoven it is difficult to separate out file system functions.

There needs to be an interface provided by the operating system software between the user and the file system. This interface can be textual (such as provided by a command line interface, such as the Unix shell, or OpenVMS DCL) or graphical (such as provided by a graphical user interface, such as file browsers). If graphical, the metaphor of the folder, containing documents, other files, and nested folders is often used (see also: directory and folder).

Unix and Unix-like operating systems

Unix-like operating systems create a virtual file system, which makes all the files on all the devices appear to exist in a single hierarchy. This means, in those systems, there is one root directory, and every file existing on the system is located under it somewhere. Unix-like systems can use a RAM disk or network shared resource as its root directory.

Unix-like systems assign a device name to each device, but this is not how the files on that device are accessed. Instead, to gain access to files on another device, the operating system must first be informed where in the directory tree those files should appear. This process is called mounting a file system. For example, to access the files on a CD-ROM, one must tell the operating system "Take the file system from this CD-ROM and make it appear under such-and-such directory". The directory given to the operating system is called the mount point – it might, for example, be /media. The /media directory exists on many Unix systems (as specified in the Filesystem Hierarchy Standard) and is intended specifically for use as a mount point for removable media such as CDs, DVDs, USB drives or floppy disks. It may be empty, or it may contain subdirectories for mounting individual devices. Generally, only the administrator (i.e. root user) may authorize the mounting of file systems.

Unix-like operating systems often include software and tools that assist in the mounting process and provide it new functionality. Some of these strategies have been coined "auto-mounting" as a reflection of their purpose.

In many situations, file systems other than the root need to be available as soon as the operating system has booted. All Unix-like systems therefore provide a facility for mounting file systems at boot time. System administrators define these file systems in the configuration file fstab (vfstab in Solaris), which also indicates options and mount points.
In some situations, there is no need to mount certain file systems at boot time, although their use may be desired thereafter. There are some utilities for Unix-like systems that allow the mounting of predefined file systems upon demand.
Removable media have become very common with microcomputer platforms. They allow programs and data to be transferred between machines without a physical connection. Common examples include USB flash drives, CD-ROMs, and DVDs. Utilities have therefore been developed to detect the presence and availability of a medium and then mount that medium without any user intervention.
Progressive Unix-like systems have also introduced a concept called supermounting; see, for example, the Linux supermount-ng project. For example, a floppy disk that has been supermounted can be physically removed from the system. Under normal circumstances, the disk should have been synchronized and then unmounted before its removal. Provided synchronization has occurred, a different disk can be inserted into the drive. The system automatically notices that the disk has changed and updates the mount point contents to reflect the new medium.
An automounter will automatically mount a file system when a reference is made to the directory atop which it should be mounted. This is usually used for file systems on network servers, rather than relying on events such as the insertion of media, as would be appropriate for removable ...


Differences between struct and classes in C++...

Differences between struct and classes in C++



In C++, a structure is a class defined with the struct keyword. Its members and base classes are public by default. A class defined with the class keyword has private members and base classes by default. This is the only difference between structs and classes in C++.

                              Aggregate classes

An aggregate class is a class with no user-declared constructors, no private or protected non-static data members, no base classes, and no virtual functionsSuch a class can be initialized with a brace-enclosed comma-separated list of initializer-clauses.The following code has the same semantics in both C and C++.

struct C
{
  int a;
  double b;
};

struct D
{
  int a;
  double b;
  C c;
};

// initialize an object of type C with an initializer-list
C c = {1, 2.0};

// D has a sub-aggregate of type C. In such cases initializer-clauses can be nested
D d = {10, 20.0, {1, 2.0}};

                                         POD-structs

A POD-struct (Plain Old Data Structure) is an aggregate class that has no non-static data members of type non-POD-struct, non-POD-union (or array of such types) or reference, and has no user-defined assignment operator and no user-defined destructor. A POD-struct could be said to be the C++ equivalent of a C struct. In most cases, a POD-struct will have the same memory layout as a corresponding struct declared in C. For this reason, POD-structs are sometimes colloquially referred to as "C-style structs".Properties shared between structs in C and POD-structs in C++
Data members are allocated so that later members have higher a

ddresses within an object, except where separated by an access-specifier.

Two POD-struct types are layout-compatible if they have the same number of nonstatic data members, and corresponding nonstatic data members (in order) have layout-compatible types.
A POD-struct may contain unnamed padding

A pointer to a POD-struct object, suitably converted using a reinterpret cast, points to its initial member and vice versa, implying that there is no padding at the beginning of a POD-struct.
A POD-struct may be used with the offsetof macro

                           Declaration and usage

C++ classes have their own members. These members include variables (including other structures and classes), functions (specific identifiers or overloaded operators) known as methods, constructors and destructors. Members are declared to be either publicly or privately accessible using the public: and private: access specifiers respectively. Any member encountered after a specifier will have the associated access until another specifier is encountered. There is also inheritance between classes which can make use of the protected: specifier

Global and local class

A class defined outside all methods is a global class because its objects can be created from anywhere in the program. If it is defined within a function body then it's a local class because objects of such a class are local to the function scope.

Basic declaration and member variables

Classes are declared with the class or struct keyword. Declaration of members are placed within this declaration.

struct person
{
  string name;
  int age;

};
class person
{
  public:
    string name;
    int age;
};
The above definitions are functionally equivalent. Either code will define objects of type person as having two public data members, name and age. The semicolons after the closing braces are mandatory.

After one of these declarations (but not both), person can be used as follows to create newly defined variables of the person datatype:

#include <iostream>
#include <string>
using namespace std;

class person
{
public:
    string name;
    int age;
};

int main()
{
  person a, b;
  a.name = "Calvin";
  b.name = "Hobbes";
  a.age = 30;
  b.age = 20;
  cout << a.name << ": " << a.age << endl;
  cout << b.name << ": " << b.age << endl;
  return 0;
}
Executing the above code will output

Calvin: 30
Hobbes: 20

Member function

An important feature of the C++ class and structure are member functions. Each datatype can have its own built-in functions (referred to as methods) that have access to all (public and private) members of the datatype. In the body of these non-static member functions, the keyword this can be used to refer to the object for which the function is called. This is commonly implemented by passing the address of the object as an implicit first argument to the function.Take the above person type as an example again:

class person
{
  std::string name;
  int age;
public:
  person() : age(5) { }
  void print() const;
};

void person::print() const
{
  cout << name << ":" << age << endl;
  /* "name" and "age" are the member variables.
     The "this" keyword is an expression whose value is the address
     of the object for which the member was invoked. Its type is
     const person*, because the function is declared const.
 */
}
In the above example the print() function is declared in the body of the class and defined by qualifying it with the name of the class followed by ::. Both name and age are private (default for class) and print() is declared as public which is necessary if it is to be used from outside the class.

With the member function print(), printing can be simplified into:

a.print();
b.print();
where a and b above are called senders, and each of them will refer to their own member variables when the print() function is executed.

It is common practice to separate the class or structure declaration (called its interface) and the definition (called its implementation) into separate units. The interface, needed by the user, is kept in a header and the implementation is kept separately in either source or compiled form.

     inheritance

The layout of non-POD classes in memory is not specified by the C++ standard. For example, many popular C++ compilers implement single inheritance by concatenation of the parent class fields with the child class fields, but this is not required by the standard. This choice of layout makes referring to a derived class via a pointer to the parent class type a trivial operation.

For example, consider

class P
{
    int x;
};
class C : public P
{
    int y;
};
An instance of P with a P* p pointing to it might look like this in memory:

+----+
|P::x|
+----+

p
An instance of C with a P* p pointing to it might look like this:

+----+----+
|P::x|C::y|
+----+----+

p
Therefore, any code that manipulates the fields of a P object can manipulate the P fields inside the C object without having to consider anything about the definition of C's fields. A properly written C++ program shouldn't make any assumptions about the layout of inherited fields, in any case. Using the static_cast or dynamic_cast type conversion operators will ensure that pointers are properly converted from one type to another.

Multiple inheritance is not as simple. If a class D inherits P and C, then the fields of both parents need to be stored in some order, but (at most) only one of the parent classes can be located at the front of the derived class. Whenever the compiler needs to convert a pointer from the D type to either P or C, the compiler will provide an automatic conversion from the address of the derived class to the address of the base class fields (typically, this is a simple offset calculation).

For more on multiple inheritance, see virtual inheritance.

Overloaded operators

For more details on this topic, see Operators in C and C++.
In C++, operators, such as + - * /, can be overloaded to suit the needs of programmers. These operators are called overloadable operators.

By convention, overloaded operators should behave nearly the same as they do in built-in datatypes (int, float, etc.), but this is not required. One can declare a structure called integer in which the variable really stores an integer, but by calling integer * integer the sum, instead of the product, one of the integers might be returned:

struct integer
{
    int i;
    integer(int j = 0) : i(j) {}
    integer operator*(const integer &k) const
    {
        return integer (i + k.i);
    }
};
The code above made use of a constructor to "construct" the return value. For clearer presentation (although this could decrease efficiency of the program if the compiler cannot optimize the statement into the equivalent one above), the above code can be rewritten as:

integer operator*(const integer &k) const
{
    integer m;
    m.i = i + k.i;
    return m;
}
Programmers can also put a prototype of the operator in the struct declaration and define the function of the operator in the global scope:

struct integer
{
    int i;
 
    integer(int j = 0) : i(j) {}

    integer operator*(const integer &k) const;
};

integer integer::operator*(const integer &k) const
{
    return integer(i * k.i);
}
i above represents the sender's own member variable, while k.i represents the member variable from the argument variable k.

The const keyword appears twice in the above code. The first occurrence, the argument const integer &k, indicated that the argument variable will not be changed by the function. The second incidence at the end of the declaration promises the compiler that the sender would not be changed by the function run.

In const integer &k, the ampersand (&) means "pass by reference". When the function is called, a pointer to the variable will be passed to the function, rather than the value of the variable.

The same overloading properties above apply also to classes.

Note that arity, associativity and precedence of operators cannot be changed.

Binary overloadable operators

Binary operators (operators with two arguments) are overloaded by declaring a function with an "identifier" operator (something) which calls one single argument. The variable on the left of the operator is the sender while that on the right is the argument.

integer i = 1;
/* we can initialize a structure variable this way as
   if calling a constructor with only the first
   argument specified. */
integer j = 3;
/* variable names are independent of the names of the
   member variables of the structure. */
integer k = i * j;
cout << k.i << endl;
'4' would be printed.

The following is a list of binary overloadable operators:

Operator General usage
+ - * / % Arithmetic calculation
^ & | << >> Bitwise calculation
< > == != <= >= Logical comparison
&& Logical conjunction
|| Logical disjunction
+= -= *= /= %=
^= &= |= <<= >>= Compound assignment
, (no general usage)

The '=' (assignment) operator between two variables of the same structure type is overloaded by default to copy the entire content of the variables from one to another. It can be overwritten with something else, if necessary.

Operators must be overloaded one by one, in other words, no overloading is associated with one another. For example, < is not necessarily the opposite of >.

Unary overloadable operators

While some operators, as specified above, takes two terms, sender on the left and the argument on the right, some operators have only one argument - the sender, and they are said to be "unary". Examples are the negative sign (when nothing is put on the left of it) and the "logical NOT" (exclamation mark, !).

Sender of unary operators may be on the left or on the right of the operator. The following is a list of unary overloadable operators:

Operator General usage Position of sender
+ - Positive / negative sign right
* & Dereference right
 ! ~ Logical / bitwise NOT right
++ -- Pre-increment / decrement right
++ -- Post-increment / decrement left
The syntax of an overloading of a unary operator, where the sender is on the right, is as follows:

return_type operator@ ()
When the sender is on the left, the declaration is:

return_type operator@ (int)
@ above stands for the operator to be overloaded. Replace return_type with the datatype of the return value (int, bool, structures etc.)

The int parameter essentially means nothing but a convention to show that the sender is on the left of the operator.

const arguments can be added to the end of the declaration if applicable.

Overloading brackets

Gnome-searchtool.svg This section's factual accuracy is disputed. (January 2009)
The square bracket [] and the round bracket () can be overloaded in C++ structures. The square bracket must contain exactly one argument, while the round bracket can contain any specific number of arguments, or no arguments.

The following declaration overloads the square bracket.

return_type operator[] (argument)

The content inside the bracket is specified in the argument part.

Round bracket is overloaded a similar way.

return_type operator() (arg1, arg2, ...)
Contents of the bracket in the operator call are specified in the second bracket.

In addition to the operators specified above, the arrow operator (->), the starred arrow (->*), the new keyword and the delete keyword can also be overloaded. These memory-or-pointer-related operators must process memory-allocating functions after overloading. Like the assignment (=) operator, they are also overloaded by default if no specific declaration is made.

Constructors
Gnome-searchtool.svg This section's factual accuracy is disputed. (January 2009)
Sometimes programmers may want their variables to take a default or specific value upon declaration. This can be done by declaring constructors.

person::person(string N, int A)
{
    name = N;
    age = A;
}
Member variables can be initialized in an initializer list, with utilization of a colon, as in the example below. This differs from the above in that it initializes (using the constructor), rather than using the assignment operator. This is more efficient for class types, since it just needs to be constructed directly; whereas with assignment, they must be first initialized using the default constructor, and then assigned a different value. Also some types (like references and const types) cannot be assigned to and therefore must be initialized in the initializer list.

person(std::string N, int A) : name(N), age(A) {}
Note that the curly braces cannot be omitted, even if empty.

Default values can be given to the last arguments to help initializing default values.

person(std::string N = "", int A = 0) : name(N), age(A) {}
When no arguments are given to the constructor in the example above, it is equivalent to calling the following constructor with no arguments (a default constructor):

person() : name(""), age(0) {}
The declaration of a constructor looks like a function with the same name as the datatype. In fact, a call to a constructor can take the form of a function call. In that case a person type variable would be the return value:

int main()
{
    person r = person("Wales", 40);
    r.print();
}
The above code creates a temporary person object, and then assigns it to r using the copy constructor. A better way of creating the object (without unnecessary copying) is:

int main()
{
    person r ("Wales", 40);
    r.print ();
}
Specific program actions, which may or may not relate to the variable, can be added as part of the constructor.

person()
{
    std::cout << "Hello!" << endl;
}
With the above constructor, a "Hello!" will be printed in case a person variable with no specific value is initialized.

Default Constructor

Default constructors are called when constructors are not defined for the classes.

class A { int b;};
//Object created using parentheses
A *a = new A(); //Calls default constructor, and b will be initialized with '0'
//Object created using no parentheses
A *a = new A; // allocate memory, then call default constructor, and b will have value '0'
//Object creation without new
A a;  //Just allocate memory, and b will have unknown garbage value
However if a user defined constructor was defined for the class, both of the above declarations will call this user defined constructor, whose defined code will be executed, but no default values will be assigned to the variable b.

Destructors

Gnome-searchtool.svg This section's factual accuracy is disputed. (January 2009)
A destructor is the reverse of a constructor. It is called when an instance of a class is destroyed, e.g. when an object of a class created in a block (set of curly braces "{}") is deleted after the closing brace, then the destructor is called automatically. It will be called upon emptying of the memory location storing the variable. Destructors can be used to release resources, such as heap-allocated memory and opened files when an instance of that class is destroyed.

The syntax for declaring a destructor is similar to that of a constructor. There is no return value and the name of the method is the same as the name of the class with a tilde (~) in front.

~person()
{
    cout << "I'm deleting " << name << " with age " << age << endl;
}

Similarities between constructors and destructors

Both have same name as the class in which they are declared.
If not declared by user both are available in a class by default but they now can only allocate and deallocate memory from the objects of a class when an object is declared or deleted.

Class templates

Main article: Template (programming)
In C++, class declarations can be generated from class templates. Such class templates represent a family of classes. An actual class declaration is obtained by instantiating the template with one or more template arguments. A template instantiated with a particular set of arguments is called a template specialization.

Properties

The syntax of C++ tries to make every aspect of a structure look like that of the basic datatypes. Therefore, overloaded operators allow structures to be manipulated just like integers and floating-point numbers, arrays of structures can be declared with the square-bracket syntax (some_structure variable_name[size]), and pointers to structures can be dereferenced in the same way as pointers to built-in datatypes.

Memory consumption

The memory consumption of a structure is at least the sum of the memory sizes of constituent variables. Take the twonums structure below as an example.

struct twonums
{
    int a;
    int b;
};
The structure consists of two integers. In many current C++ compilers, integers are 32-bit integers by default, so each of the member variables consume four bytes of memory. The entire structure, therefore, consumes at least (or exactly) eight bytes of memory, as follows.

+----+----+
| a  | b  |
+----+----+
However, the compiler may add padding between the variables or at the end of the structure to ensure proper data alignment for a given computer architecture, often padding variables to be 32-bit aligned. For example, the structure

struct bytes_and_such
{
   char c;
   char C;
   short int s;
   int i;
   double d;
};
could look like

+-+-+--+--+--+--+--------+
|c|C|XX|s |  i  |   d    |
+-+-+--+--+--+--+--------+
in memory, where XX are two unused bytes.

As structures may make use of pointers and arrays to declare and initialize its member variables, memory consumption of structures is not necessarily constant. Another example of non-constant memory size is template structures.

Bit Fields

Bit Fields are used to define the class members that can occupy less storage than an integral type. This field is applicable only for integral type(int, char, short, long...) excludes float or double.

struct A
{
unsigned a:2; // possible values 0..3,  occupies first 2 bits of int
unsigned b:3; // possible values 0..7,  occupies next 3 bits of int
unsigned :0;  // moves to end of next integral type
unsigned c:2;
unsigned :4;  // pads 4 bits in between c & d
unsigned d:1;
unsigned e:3;
};
Memory structure
         4 byte int  4 byte int
        [1][2][3][4][5][6][7][8]
        [1]                      [2]                      [3]                      [4]
        [a][a][b][b][b][ ][ ][ ] [ ][ ][ ][ ][ ][ ][ ][ ] [ ][ ][ ][ ][ ][ ][ ][ ] [ ][ ][ ][ ][ ][ ][ ][ ]

        [5]                      [6]                      [7]                      [8]
        [c][c][ ][ ][ ][ ][d][e] [e][e][ ][ ][ ][ ][ ][ ] [ ][ ][ ][ ][ ][ ][ ][ ] [ ][ ][ ][ ][ ][ ][ ][ ]
Bit fields are not allowed in union, it is applicable only for the classes defined using keyword struct or class

Pass by reference

For more details on this topic, see evaluation strategy.
Many programmers prefer to use the ampersand (&) to declare the arguments of a function involving structures. This is because by using the dereferencing ampersand only one word (typically 4 bytes on a 32 bit machine, 8 bytes on a 64 bit machine) is required to be passed into the function, namely the memory location to the variable. Otherwise, if pass-by-value is used, the argument needs to be copied every time the function is called, which is costly with large structures.

Since pass-by-reference exposes the original structure to be modified by the function, the const keyword should be used to guarantee that the function does not modify the parameter (see const-correctness), when this is not intended.

The this keyword

Main article: this (computer science)
To facilitate structures' ability to reference themselves, C++ implements the this keyword for all member functions. The this keyword acts as a pointer to the current object.[11] Its type is that of a pointer to the current object.

The this keyword is especially important for member functions with the structure itself as the return value:

complex& operator+=(const complex & c)
{
    realPart += c.realPart;
    imagPart += c.imagPart;
    return *this;
}

Friendship and inheritance....

                    Friendship and inheritance




                                            Friend functions

In principle, private and protected members of a class cannot be accessed from outside the same class in which they are declared. However, this rule does not apply to "friends".

Friends are functions or classes declared with the friend keyword.

A non-member function can access the private and protected members of a class if it is declared a friend of that class. That is done by including a declaration of this external function within the class, and preceding it with the keywordfriend:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// friend functions
#include <iostream>
using namespace std;

class Rectangle {
    int width, height;
  public:
    Rectangle() {}
    Rectangle (int x, int y) : width(x), height(y) {}
    int area() {return width * height;}
    friend Rectangle duplicate (const Rectangle&);
};

Rectangle duplicate (const Rectangle& param)
{
  Rectangle res;
  res.width = param.width*2;
  res.height = param.height*2;
  return res;
}

int main () {
  Rectangle foo;
  Rectangle bar (2,3);
  foo = duplicate (bar);
  cout << foo.area() << '\n';
  return 0;
}
24


The duplicate function is a friend of class Rectangle. Therefore, function duplicate is able to access the members widthand height (which are private) of different objects of type Rectangle. Notice though that neither in the declaration ofduplicate nor in its later use in main, member function duplicate is considered a member of class Rectangle. It isn't! It simply has access to its private and protected members without being a member.
Typical use cases of friend functions are operations that are conducted between two different classes accessing private or protected members of both. 

                                             Friend classes



Similar to friend functions, a friend class is a class whose members have access to the private or protected members of another class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// friend class
#include <iostream>
using namespace std;

class Square;

class Rectangle {
    int width, height;
  public:
    int area ()
      {return (width * height);}
    void convert (Square a);
};

class Square {
  friend class Rectangle;
  private:
    int side;
  public:
    Square (int a) : side(a) {}
};

void Rectangle::convert (Square a) {
  width = a.side;
  height = a.side;
}
  
int main () {
  Rectangle rect;
  Square sqr (4);
  rect.convert(sqr);
  cout << rect.area();
  return 0;
}
In this example, class Rectangle is a friend of class Square allowing Rectangle's member functions to access private and protected members of Square. More concretely, Rectangle accesses the member variable Square::side, which describes the side of the square.
There is something else new in this example: at the beginning of the program, there is an empty declaration of classSquare. This is necessary because class Rectangle uses Square (as a parameter in member convert), and Square usesRectangle (declaring it a friend).
Friendships are never corresponded unless specified: In our example, Rectangle is considered a friend class by Square, but Square is not considered a friend by Rectangle. Therefore, the member functions of Rectangle can access the protected and private members of Square but not the other way around. Of course, Square could also be declared friend ofRectangle, if needed, granting such an access.
Another property of friendships is that they are not transitive: The friend of a friend is not considered a friend unless explicitly specified.

                   Inheritance between classes



Classes in C++ can be extended, creating new classes which retain characteristics of the base class. This process, known as inheritance, involves a base class and a derived class: The derived class inherits the members of the base class, on top of which it can add its own members.
For example, let's imagine a series of classes to describe two kinds of polygons: rectangles and triangles. These two polygons have certain common properties, such as the values needed to calculate their areas: they both can be described simply with a height and a width (or base).
This could be represented in the world of classes with a class Polygon from which we would derive the two other ones:Rectangle and Triangle:

 


The Polygon class would contain members that are common for both types of polygon. In our case: width and height. And Rectangle and Triangle would be its derived classes, with specific features that are different from one type of polygon to the other.
Classes that are derived from others inherit all the accessible members of the base class. That means that if a base class includes a member A and we derive a class from it with another member called B, the derived class will contain both member A and member B.
The inheritance relationship of two classes is declared in the derived class. Derived classes definitions use the following syntax:
class derived_class_name: public base_class_name{ /*...*/ };Where derived_class_name is the name of the derived class and base_class_name is the name of the class on which it is based. The public access specifier may be replaced by any one of the other access specifiers (protected or private). This access specifier limits the most accessible level for the members inherited from the base class: The members with a more accessible level are inherited with this level instead, while the members with an equal or more restrictive access level keep their restrictive level in the derived class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// derived classes
#include <iostream>
using namespace std;

class Polygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b;}
 };

class Rectangle: public Polygon {
  public:
    int area ()
      { return width * height; }
 };

class Triangle: public Polygon {
  public:
    int area ()
      { return width * height / 2; }
  };
  
int main () {
  Rectangle rect;
  Triangle trgl;
  rect.set_values (4,5);
  trgl.set_values (4,5);
  cout << rect.area() << '\n';
  cout << trgl.area() << '\n';
  return 0;
}
20
10


The objects of the classes Rectangle and Triangle each contain members inherited from Polygon. These are: width,height and set_values.
The protected access specifier used in class Polygon is similar to private. Its only difference occurs in fact with inheritance: When a class inherits another one, the members of the derived class can access the protected members inherited from the base class, but not its private members.
By declaring width and height as protected instead of private, these members are also accessible from the derived classes Rectangle and Triangle, instead of just from members of Polygon. If they were public, they could be accessed just from anywhere.
We can summarize the different access types according to which functions can access them in the following way:

Accesspublicprotectedprivate
members of the same classyesyesyes
members of derived classyesyesno
not membersyesnono

Where "not members" represents any access from outside the class, such as from main, from another class or from a function.
In the example above, the members inherited by Rectangle and Triangle have the same access permissions as they had in their base class Polygon:

1
2
3
4
5
Polygon::width           // protected access
Rectangle::width         // protected access

Polygon::set_values()    // public access
Rectangle::set_values()  // public access  


This is because the inheritance relation has been declared using the public keyword on each of the derived classes:

 
class Rectangle: public Polygon { /* ... */ }


This public keyword after the colon (:) denotes the most accessible level the members inherited from the class that follows it (in this case Polygon) will have from the derived class (in this case Rectangle). Since public is the most accessible level, by specifying this keyword the derived class will inherit all the members with the same levels they had in the base class.
With protected, all public members of the base class are inherited as protected in the derived class. Conversely, if the most restricting access level is specified (private), all the base class members are inherited as private.
For example, if daughter were a class derived from mother that we defined as:
 
class Daughter: protected Mother;


This would set protected as the less restrictive access level for the members of Daughter that it inherited from mother. That is, all members that were public in Mother would become protected in Daughter. Of course, this would not restrictDaughter from declaring its own public members. That less restrictive access level is only set for the members inherited from Mother.
If no access level is specified for the inheritance, the compiler assumes private for classes declared with keyword classand public for those declared with struct.
What is inherited from the base class?
In principle, a derived class inherits every member of a base class except:
  • its constructors and its destructor
  • its assignment operator members (operator=)
  • its friends
  • its private members

Although the constructors and destructors of the base class are not inherited as constructors and destructors in the derived class, they are still called by the derived class's constructor. Unless otherwise specified, the constructors of derived classes call the default constructors of their base classes (i.e., the constructor taking no arguments), which must exist.
Calling a different constructor of a base class is possible, using the same syntax as to initialize member variables in the initialization list:

derived_constructor_name (parameters) : base_constructor_name (parameters) {...}


For example: 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// constructors and derived classes
#include <iostream>
using namespace std;

class Mother {
  public:
    Mother ()
      { cout << "Mother: no parameters\n"; }
    Mother (int a)
      { cout << "Mother: int parameter\n"; }
};

class Daughter : public Mother {
  public:
    Daughter (int a)
      { cout << "Daughter: int parameter\n\n"; }
};

class Son : public Mother {
  public:
    Son (int a) : Mother (a)
      { cout << "Son: int parameter\n\n"; }
};

int main () {
  Daughter kelly(0);
  Son bud(0);
  
  return 0;
}
Mother: no parameters
Daughter: int parameter

Mother: int parameter
Son: int parameter


Notice the difference between which Mother's constructor is called when a new Daughter object is created and which when it is a Son object. The difference is due to the different constructor declarations of Daughter and Son:


1
2
Daughter (int a)          // nothing specified: call default constructor
Son (int a) : Mother (a)  // constructor specified: call this specific constructor 


                                 Multiple inheritance
A class may inherit from more than one class by simply specifying more base classes, separated by commas, in the list of a class's base classes (i.e., after the colon). For example, if the program had a specific class to print on screen calledOutput, and we wanted our classes Rectangle and Triangle to also inherit its members in addition to those of Polygon we could write:

1
2
class Rectangle: public Polygon, public Output;
class Triangle: public Polygon, public Output; 


Here is the complete example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// multiple inheritance
#include <iostream>
using namespace std;

class Polygon {
  protected:
    int width, height;
  public:
    Polygon (int a, int b) : width(a), height(b) {}
};

class Output {
  public:
    static void print (int i);
};

void Output::print (int i) {
  cout << i << '\n';
}

class Rectangle: public Polygon, public Output {
  public:
    Rectangle (int a, int b) : Polygon(a,b) {}
    int area ()
      { return width*height; }
};

class Triangle: public Polygon, public Output {
  public:
    Triangle (int a, int b) : Polygon(a,b) {}
    int area ()
      { return width*height/2; }
};
  
int main () {
  Rectangle rect (4,5);
  Triangle trgl (4,5);
  rect.print (rect.area());
  Triangle::print (trgl.area());
  return 0;
}
20
10