2W五千字的C++基础知识整理汇总(一)

简介: 笔记

大家好,我是阿秀。

最近发现一篇两万五千字的C++基础知识大汇总,可把我高兴坏了。

白嫖,必须白嫖

感谢亮哥的整理和手机


一 、从”hello world“ 入门C++!


C++总览简介

C++ 是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程和泛型编程。

C++ 被认为是一种中级语言,它综合了高级语言和低级语言的特点。

C++ 是由 Bjarne Stroustrup 于 1979 年在新泽西州美利山贝尔实验室开始设计开发的。C++ 进一步扩充和完善了 C 语言,最初命名为带类的C,后来在 1983 年更名为 C++。

C++ 是 C 的一个超集,事实上,任何合法的 C 程序都是合法的 C++ 程序。


注意:使用静态类型的编程语言是在编译时执行类型检查,而不是在运行时执行类型检查。


面向对象程序设计

c++最大的亮点就是面向对象程序设计理念的运用。包括面向对象开发的四大特性:

  •    封装
  •    抽象
  •    继承
  •    多态


C++的组成部分


标准的 C++ 由三个重要部分组成:

  •    核心语言,提供了所有构件块,包括变量、数据类型和常量,等等。
  •    C++ 标准库,提供了大量的函数,用于操作文件、字符串等。
  •    标准模板库(STL),提供了大量的方法,用于操作数据结构等。


C++的标准

对一门编程语言来说,遵循统一的标准是必需的。下面的表格列出了c++标准的发展历史。


发布时间 文档 通称 备注
2015 ISO/IEC TS 19570:2015 - 用于并行计算的扩展
2015 ISO/IEC TS 18822:2015 - 文件系统
2014 ISO/IEC 14882:2014 C++14 第四个C++标准
2011 ISO/IEC TR 24733:2011 - 十进制浮点数扩展
2011 ISO/IEC 14882:2011 C++11 第三个C++标准
2010 ISO/IEC TR 29124:2010 - 数学函数扩展
2007 ISO/IEC TR 19768:2007 C++TR1 C++技术报告:库扩展
2006 ISO/IEC TR 18015:2006 - C++性能技术报告
2003 ISO/IEC 14882:2003 C++03 第二个C++标准


C++ 程序结构

让我们看一段简单的代码,可以输出单词 Hello World。

#include <iostream>
using namespace std;
// main() 是程序开始执行的地方
int main()
{
cout << "Hello World"; // 输出 Hello World
return 0;
}


让我们一起来研究一下上面的代码结构:

C++ 语言定义了一些头文件,这些头文件包含了程序中必需的或有用的信息。上面这段程序中,包含了头文件 。

下一行 using namespace std; 告诉编译器使用 std 命名空间。命名空间是 C++ 中一个相对新的概念。

下一行 // main() 是程序开始执行的地方 是一个单行注释。单行注释以 // 开头,在行末结束。

下一行 int main() 是主函数,程序从这里开始执行。

下一行 cout << "Hello World"; 会在屏幕上显示消息 "Hello World"。

下一行 return 0; 终止 main( )函数,并向调用进程返回值 0。


C++ 中的分号 & 语句块

在 C++ 中,分号是语句结束符。也就是说,每个语句必须以分号结束。它表明一个逻辑实体的结束。


例如:下面就一共有两条语句。

x = y;
y = x+1;


语句块是一组使用大括号括起来的按逻辑连接的语句。例如:

{
cout << "Hello World"; // 输出 Hello World
return 0;
}


C++ 关键字

下表列出了 C++ 中的保留字。这些保留字不能作为常量名、变量名或其他标识符名称。


asm else new this
auto enum operator throw
bool explicit private true
break export protected try
case extern public typedef
catch false register typeid
char float reinterpret_cast typename
class for return union
const friend short unsigned
const_cast goto signed using
continue if sizeof virtual
default inline static void
delete int static_cast volatile
do long struct wchar_t
double mutable switch while
dynamic_cast namespace template


C++ 标识符

C++ 标识符是用来标识变量、函数、类、模块,或任何其他用户自定义项目的名称。一个标识符以字母 A-Z 或 a-z 或下划线 _ 开始,后跟零个或多个字母、下划线和数字(0-9),不允许改变标识符组成规则。

下面列出几个有效的标识符:

test
_temp

二 、 c++基本数据类型及流控制语句详解


C++ 数组

C++ 支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。

数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 numbers[0]、numbers[1]、...、numbers[99] 来代表一个个单独的变量。数组中的特定元素可以通过索引访问。

所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。


声明数组

在 C++ 中要声明一个数组,需要指定元素的类型和元素的数量,如下所示:

type arrayName [ arraySize ];


这叫做一维数组。arraySize 必须是一个大于零的整数常量,type 可以是任意有效的 C++ 数据类型。例如,要声明一个类型为 double 的包含 10 个元素的数组 balance,声明语句如下:


double balance[10];


现在 balance 是一个可用的数组,可以容纳 10 个类型为 double 的数字。


初始化数组

在 C++ 中,可以逐个初始化数组,也可以使用一个初始化语句,如下所示:

double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};


大括号 { } 之间的值的数目不能大于我们在数组声明时在方括号 [ ] 中指定的元素数目。

如果省略掉了数组的大小,数组的大小则为初始化时元素的个数。因此,如果:


double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};


将创建一个数组,它与前一个实例中所创建的数组是完全相同的。

下面是一个为数组中某个元素赋值的实例:

balance[4] = 50.0;


上述的语句把数组中第五个元素的值赋为 50.0。所有的数组都是以 0 作为它们第一个元素的索引,也被称为基索引,数组的最后一个索引是数组的总大小减去 1。以下是上面所讨论的数组的的图形表示:


访问数组元素

数组元素可以通过数组名称加索引进行访问。元素的索引是放在方括号内,跟在数组名称的后边。例如:

double salary = balance[9];


上面的语句将把数组中第 10 个元素的值赋给 salary 变量。下面的实例使用了上述的三个概念,即,声明数组、数组赋值、访问数组:

#include <iostream>
using namespace std;
#include <iomanip>
using std::setw;
int main ()
{
   int n[ 10 ]; // n 是一个包含 10 个整数的数组
   // 初始化数组元素          
   for ( int i = 0; i < 10; i++ )
   {
      n[ i ] = i + 100; // 设置元素 i 为 i + 100
   }
   cout << "Element" << setw( 13 ) << "Value" << endl;
   // 输出数组中每个元素的值                     
   for ( int j = 0; j < 10; j++ )
   {
      cout << setw( 7 )<< j << setw( 13 ) << n[ j ] << endl;
   }
   return 0;
}

C++ 字符串

C++ 提供了以下两种类型的字符串表示形式:

  • C 风格字符串
  • C++ 引入的 string 类类型


C 风格字符串

C 风格的字符串起源于 C 语言,并在 C++ 中继续得到支持。字符串实际上是使用 null 字符 '\0' 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。

下面的声明和初始化创建了一个 "Hello" 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 "Hello" 的字符数多一个。

char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};


依据数组初始化规则,可以把上面的语句写成以下语句:


char greeting[] = "Hello";


以下是 C/C++ 中定义的字符串的内存表示:

其实,不需要把 null 字符放在字符串常量的末尾。C++ 编译器会在初始化数组时,自动把 '\0' 放在字符串的末尾。让我们尝试输出上面的字符串:

实例

#include <iostream> 
using namespace std;
 int main (){ 
   char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};   
    cout << "Greeting message: ";  
     cout << greeting << endl;  
       return 0;
 }

当上面的代码被编译和执行时,它会产生下列结果:

Greeting message: Hello


C++ 中有大量的函数用来操作以 null 结尾的字符串:supports a wide range of functions that manipulate null-terminated strings:

序号 函数 & 目的

1

strcpy(s1, s2); 复制字符串 s2 到字符串 s1。

2

strcat(s1, s2); 连接字符串 s2 到字符串 s1 的末尾。

3

strlen(s1); 返回字符串 s1 的长度。

4

strcmp(s1, s2); 如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回值小于 0;如果 s1>s2 则返回值大于 0。

5

strchr(s1, ch); 返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。

6

strstr(s1, s2); 返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。

下面的实例使用了上述的一些函数:

实例

#include <iostream>
#include <cstring>
using namespace std;
int main ()
{
   char str1[11] = "Hello";
   char str2[11] = "World";
   char str3[11];
   int  len ;
   // 复制 str1 到 str3
   strcpy( str3, str1);
   cout << "strcpy( str3, str1) : " << str3 << endl;
   // 连接 str1 和 str2
   strcat( str1, str2);
   cout << "strcat( str1, str2): " << str1 << endl;
   // 连接后,str1 的总长度
   len = strlen(str1);
   cout << "strlen(str1) : " << len << endl;
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

strcpy( str3, str1) : Hellostrcat( str1, str2): HelloWorldstrlen(str1) : 10C++ 中的 String 类


C++ 中的 string 类

C++ 标准库提供了 string 类类型,支持上述所有的操作,另外还增加了其他更多的功能。现在让我们先来看看下面这个实例:

实例

#include <iostream>
#include <string>
using namespace std;
int main ()
{
   string str1 = "Hello";
   string str2 = "World";
   string str3;
   int  len ;
   // 复制 str1 到 str3
   str3 = str1;
   cout << "str3 : " << str3 << endl;
   // 连接 str1 和 str2
   str3 = str1 + str2;
   cout << "str1 + str2 : " << str3 << endl;
   // 连接后,str3 的总长度
   len = str3.size();
   cout << "str3.size() :  " << len << endl;
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

str3 : Hello
str1 + str2 : HelloWorld
str3.size() : 10


C++ 循环

有的时候,可能需要多次执行同一块代码。一般情况下,语句是顺序执行的:函数中的第一个语句先执行,接着是第二个语句,依此类推。

编程语言提供了允许更为复杂的执行路径的多种控制结构。

循环语句允许我们多次执行一个语句或语句组,下面是大多数编程语言中循环语句的一般形式:


循环类型

C++ 编程语言提供了以下几种循环类型。

循环类型 描述

while 循环

当给定条件为真时,重复语句或语句组。它会在执行循环主体之前测试条件。

for 循环

多次执行一个语句序列,简化管理循环变量的代码。

do...while 循环

除了它是在循环主体结尾测试条件外,其他与 while 语句类似。

嵌套循环

可以在 while、for 或 do..while 循环内使用一个或多个循环。


循环控制语句

循环控制语句更改执行的正常序列。当执行离开一个范围时,所有在该范围中创建的自动对象都会被销毁。

C++ 提供了下列的控制语句。

控制语句 描述

break 语句

终止 loop 或 switch 语句,程序流将继续执行紧接着 loop 或 switch 的下一条语句。

continue 语句

引起循环跳过主体的剩余部分,立即重新开始测试条件。

goto 语句

将控制转移到被标记的语句。但是不建议在程序中使用 goto 语句。

无限循环

如果条件永远不为假,则循环将变成无限循环。for 循环在传统意义上可用于实现无限循环。由于构成循环的三个表达式中任何一个都不是必需的,可以将某些条件表达式留空来构成一个无限循环。

实例


#include <iostream>
using namespace std;
int main ()
{
   for( ; ; )
   {
      printf("This loop will run forever.\n");
   }
   return 0;
}


当条件表达式不存在时,它被假设为真。也可以设置一个初始值和增量表达式,但是一般情况下,C++ 程序员偏向于使用 for(;;) 结构来表示一个无限循环。

注意:可以按 Ctrl + C 键终止一个无限循环。


C++ 判断

判断结构要求程序员指定一个或多个要评估或测试的条件,以及条件为真时要执行的语句(必需的)和条件为假时要执行的语句(可选的)。

下面是大多数编程语言中典型的判断结构的一般形式:


判断语句


C++ 编程语言提供了以下类型的判断语句。

语句 描述

if 语句

一个 if 语句 由一个布尔表达式后跟一个或多个语句组成。

if...else 语句

一个 if 语句 后可跟一个可选的 else 语句,else 语句在布尔表达式为假时执行。

嵌套 if 语句

可以在一个 if 或 else if 语句内使用另一个 if 或 else if 语句。

switch 语句

一个 switch 语句允许测试一个变量等于多个值时的情况。

嵌套 switch 语句

可以在一个 switch 语句内使用另一个 switch 语句。



三 、 c++进阶 基本输入输出、指针、引用


C++ 基本的输入输出


今天我们来熟悉一下C++ 编程中最基本和最常见的 I/O 操作。

C++ 的 I/O 发生在流中,流是字节序列。如果字节流是从设备(如键盘、磁盘驱动器、网络连接等)流向内存,这叫做输入操作。如果字节流是从内存流向设备(如显示屏、打印机、磁盘驱动器、网络连接等),这叫做输出操作。


I/O 库头文件

下列的头文件在 C++ 编程中很重要。

头文件

函数和描述

<iostream>

该文件定义了 cin、cout、cerr 和 clog 对象,分别对应于标准输入流、标准输出流、非缓冲标准错误流和缓冲标准错误流。

<iomanip>

该文件通过所谓的参数化的流操纵器(比如 setw 和 setprecision),来声明对执行标准化 I/O 有用的服务。

<fstream>

该文件为用户控制的文件处理声明服务。我们将在文件和流的相关章节讨论它的细节。


标准输出流(cout)

预定义的对象 cout 是 iostream 类的一个实例。cout 对象"连接"到标准输出设备,通常是显示屏。cout 是与流插入运算符 << 结合使用的,如下所示:

实例

#include <iostream>
using namespace std;
int main( )
{
   char str[] = "Hello C++";
   cout << "Value of str is : " << str << endl;
}


当上面的代码被编译和执行时,它会产生下列结果:


Value of str is : Hello C++

C++ 编译器根据要输出变量的数据类型,选择合适的流插入运算符来显示值。<< 运算符被重载来输出内置类型(整型、浮点型、double 型、字符串和指针)的数据项。

流插入运算符 << 在一个语句中可以多次使用,如上面实例中所示,endl 用于在行末添加一个换行符。


标准输入流(cin)

预定义的对象 cin 是 iostream 类的一个实例。cin 对象附属到标准输入设备,通常是键盘。cin 是与流提取运算符 >> 结合使用的,如下所示:

实例

#include <iostream>
using namespace std;
int main( )
{
   char name[50];
   cout << "请输入您的名称:";
   cin >> name;
   cout << "您的名称是:" << name << endl;
}

当上面的代码被编译和执行时,它会提示用户输入名称。当用户输入一个值,并按回车键,就会看到下列结果:

请输入您的名称:cplusplus
您的名称是:cplusplus

C++ 编译器根据要输入值的数据类型,选择合适的流提取运算符来提取值,并把它存储在给定的变量中。

流提取运算符 >> 在一个语句中可以多次使用,如果要求输入多个数据,可以使用如下语句:


cin >> name >> age;

这相当于下面两个语句:


cin >> name;
cin >> age;


标准错误流(cerr)

预定义的对象 cerr 是 iostream 类的一个实例。cerr 对象附属到标准错误设备,通常也是显示屏,但是 cerr 对象是非缓冲的,且每个流插入到 cerr 都会立即输出。

cerr 也是与流插入运算符 << 结合使用的,如下所示:

实例

#include <iostream>
using namespace std;
int main( )
{
   char str[] = "Unable to read....";
   cerr << "Error message : " << str << endl;
}

当上面的代码被编译和执行时,它会产生下列结果:


Error message : Unable to read....


标准日志流(clog)

预定义的对象 clog 是 iostream 类的一个实例。clog 对象附属到标准错误设备,通常也是显示屏,但是 clog 对象是缓冲的。这意味着每个流插入到 clog 都会先存储在缓冲在,直到缓冲填满或者缓冲区刷新时才会输出。

clog 也是与流插入运算符 << 结合使用的,如下所示:

实例

#include <iostream>
using namespace std;
int main( )
{
   char str[] = "Unable to read....";
   clog << "Error message : " << str << endl;
}

当上面的代码被编译和执行时,它会产生下列结果:


Error message : Unable to read....


通过这些小实例,我们无法区分 cout、cerr 和 clog 的差异,但在编写和执行大型程序时,它们之间的差异就变得非常明显。所以良好的编程实践告诉我们,使用 cerr 流来显示错误消息,而其他的日志消息则使用 clog 流来输出。


C++ 指针

学习 C++ 的指针既简单又有趣。通过指针,可以简化一些 C++ 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。所以,想要成为一名优秀的 C++ 程序员,学习指针是很有必要的。

每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。请看下面的实例,它将输出定义的变量地址:

实例

#include <iostream>
using namespace std;
int main ()
{
   int  var1;
   char var2[10];
   cout << "var1 变量的地址:";
   cout << &var1 << endl;
   cout << "var2 变量的地址:";
   cout << &var2 << endl;
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:



var1 变量的地址:0xbfebd5c0
var2 变量的地址:0xbfebd5b6

通过上面的实例,我们了解了什么是内存地址以及如何访问它。接下来让我们看看什么是指针。


什么是指针?

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:

type *var-name;

在这里,type 是指针的基类型,它必须是一个有效的 C++ 数据类型,var-name 是指针变量的名称。用来声明指针的星号 * 与乘法中使用的星号是相同的。但是,在这个语句中,星号是用来指定一个变量是指针。以下是有效的指针声明:

int *ip; /* 一个整型的指针 */
double *dp; /* 一个 double 型的指针 */
float *fp; /* 一个浮点型的指针 */
char *ch; /* 一个字符型的指针 */


所有指针的值的实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。


C++ 中使用指针

使用指针时会频繁进行以下几个操作:定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。这些是通过使用一元运算符 *来返回位于操作数所指定地址的变量的值。下面的实例涉及到了这些操作:

实例

#include <iostream>
using namespace std;
int main ()
{
   int  var = 20;   // 实际变量的声明
   int  *ip;        // 指针变量的声明
   ip = &var;       // 在指针变量中存储 var 的地址
   cout << "Value of var variable: ";
   cout << var << endl;
   // 输出在指针变量中存储的地址
   cout << "Address stored in ip variable: ";
   cout << ip << endl;
   // 访问指针中地址的值
   cout << "Value of *ip variable: ";
   cout << *ip << endl;
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:


Value of var variable: 20
Address stored in ip variable: 0xbfc601ac
Value of *ip variable: 20


C++ 引用

引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。


C++ 引用 vs 指针

引用很容易与指针混淆,它们之间有三个主要的不同:

  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。


C++ 中创建引用

试想变量名称是变量附属在内存位置中的标签,可以把引用当成是变量附属在内存位置中的第二个标签。因此,可以通过原始变量名称或引用来访问变量的内容。例如:


int i = 17;

我们可以为 i 声明引用变量,如下所示:


int& r = i;
double& s = d;

在这些声明中,& 读作引用。因此,第一个声明可以读作 "r 是一个初始化为 i 的整型引用",第二个声明可以读作 "s 是一个初始化为 d 的 double 型引用"。下面的实例使用了 int 和 double 引用:

实例

#include <iostream>
using namespace std;
int main ()
{
   // 声明简单的变量
   int    i;
   double d;
   // 声明引用变量
   int&    r = i;
   double& s = d;
   i = 5;
   cout << "Value of i : " << i << endl;
   cout << "Value of i reference : " << r  << endl;
   d = 11.7;
   cout << "Value of d : " << d << endl;
   cout << "Value of d reference : " << s  << endl;
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Value of i : 5
Value of i reference : 5
Value of d : 11.7
Value of d reference : 11.7

引用通常用于函数参数列表和函数返回值。下面列出了 C++ 程序员必须清楚的两个与 C++ 引用相关的重要概念:

概念 描述

把引用作为参数

C++ 支持把引用作为参数传给函数,这比传一般的参数更安全。

把引用作为返回值

可以从 C++ 函数中返回引用,就像返回其他数据类型一样。



四、 C++ 类与对象初探:继承和重载


C++ 类 & 对象

C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核心特性,通常被称为用户定义的类型。

类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法。类中的数据和方法称为类的成员。函数在一个类中被称为类的成员。


C++ 类定义

定义一个类,本质上是定义一个数据类型的蓝图。这实际上并没有定义任何数据,但它定义了类的名称意味着什么,也就是说,它定义了类的对象包括了什么,以及可以在这个对象上执行哪些操作。

类定义是以关键字 class 开头,后跟类的名称。类的主体是包含在一对花括号中。类定义后必须跟着一个分号或一个声明列表。例如,我们使用关键字 class 定义 Box 数据类型,如下所示:

class Box
{
   public:
      double length;   // 盒子的长度
      double breadth;  // 盒子的宽度
      double height;   // 盒子的高度
};

关键字 public 确定了类成员的访问属性。在类对象作用域内,公共成员在类的外部是可访问的。也可以指定类的成员为 private 或 protected。


定义 C++ 对象

类提供了对象的蓝图,所以基本上,对象是根据类来创建的。声明类的对象,就像声明基本类型的变量一样。下面的语句声明了类 Box 的两个对象:

Box Box1; // 声明 Box1,类型为 Box Box Box2; // 声明 Box2,类型为 Box对象
Box1 和 Box2 都有它们各自的数据成员。


访问数据成员

类的对象的公共数据成员可以使用直接成员访问运算符 (.) 来访问。为了更好地理解这些概念,让我们尝试一下下面的实例:

实例

#include <iostream>
using namespace std;
class Box
{
   public:
      double length;   // 长度
      double breadth;  // 宽度
      double height;   // 高度
};
int main( )
{
   Box Box1;        // 声明 Box1,类型为 Box
   Box Box2;        // 声明 Box2,类型为 Box
   double volume = 0.0;     // 用于存储体积
   // box 1 详述
   Box1.height = 5.0; 
   Box1.length = 6.0; 
   Box1.breadth = 7.0;
   // box 2 详述
   Box2.height = 10.0;
   Box2.length = 12.0;
   Box2.breadth = 13.0;
   // box 1 的体积
   volume = Box1.height * Box1.length * Box1.breadth;
   cout << "Box1 的体积:" << volume <<endl;
   // box 2 的体积
   volume = Box2.height * Box2.length * Box2.breadth;
   cout << "Box2 的体积:" << volume <<endl;
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:


Box1 的体积:210
Box2 的体积:1560

需要注意的是,私有的成员和受保护的成员不能使用直接成员访问运算符 (.) 来直接访问。



C++ 继承


面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行时间的效果。

当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。

继承代表了 is a 关系。例如,哺乳动物是动物,狗是哺乳动物,因此,狗是动物,等等。


基类 & 派生类

一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数。定义一个派生类,我们使用一个类派生列表来指定基类。类派生列表以一个或多个基类命名,形式如下:


class derived-class: access-specifier base-class

其中,访问修饰符 access-specifier 是 public、protected 或 private 其中的一个,base-class 是之前定义过的某个类的名称。如果未使用访问修饰符 access-specifier,则默认为 private。

假设有一个基类 Shape,Rectangle 是它的派生类,如下所示:

实例

#include <iostream>
using namespace std;
// 基类
class Shape 
{
   public:
      void setWidth(int w)
{
         width = w;
      }
      void setHeight(int h)
{
         height = h;
      }
   protected:
      int width;
      int height;
};
// 派生类
class Rectangle: public Shape
{
   public:
      int getArea()
{ 
         return (width * height); 
      }
};
int main(void)
{
   Rectangle Rect;
   Rect.setWidth(5);
   Rect.setHeight(7);
   // 输出对象的面积
   cout << "Total area: " << Rect.getArea() << endl;
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:


Total area: 35


访问控制和继承

派生类可以访问基类中所有的非私有成员。因此基类成员如果不想被派生类的成员函数访问,则应在基类中声明为 private。

我们可以根据访问权限总结出不同的访问类型,如下所示:

访问 public protected private

同一个类

yes

yes

yes

派生类

yes

yes

no

外部的类

yes

no

no

一个派生类继承了所有的基类方法,但下列情况除外:

  • 基类的构造函数、析构函数和拷贝构造函数。
  • 基类的重载运算符。
  • 基类的友元函数。


继承类型

当一个类派生自基类,该基类可以被继承为 public、protected 或 private 几种类型。继承类型是通过上面讲解的访问修饰符 access-specifier 来指定的。

我们几乎不使用 protected private 继承,通常使用 public 继承。当使用不同类型的继承时,遵循以下几个规则:

  • 公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
  • 保护继承(protected):当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
  • 私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。


多继承

多继承即一个子类可以有多个父类,它继承了多个父类的特性。

C++ 类可以从多个类继承成员,语法如下:

class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
{
<派生类类体>
};

其中,访问修饰符继承方式是 public、protected 或 private 其中的一个,用来修饰每个基类,各个基类之间用逗号分隔,如上所示。现在让我们一起看看下面的实例:

实例

#include <iostream>
using namespace std;
// 基类 Shape
class Shape 
{
   public:
      void setWidth(int w)
{
         width = w;
      }
      void setHeight(int h)
{
         height = h;
      }
   protected:
      int width;
      int height;
};
// 基类 PaintCost
class PaintCost 
{
   public:
      int getCost(int area)
{
         return area * 70;
      }
};
// 派生类
class Rectangle: public Shape, public PaintCost
{
   public:
      int getArea()
{ 
         return (width * height); 
      }
};
int main(void)
{
   Rectangle Rect;
   int area;
   Rect.setWidth(5);
   Rect.setHeight(7);
   area = Rect.getArea();
   // 输出对象的面积
   cout << "Total area: " << Rect.getArea() << endl;
   // 输出总花费
   cout << "Total paint cost: $" << Rect.getCost(area) << endl;
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:


Total area: 35
Total paint cost: $2450


相关文章
|
5月前
|
C语言 C++ 开发者
C++基础知识(一:命名空间的各种使用方法)
C++在C的基础上引入了更多的元素,例如类,类的私密性要比C中的结构体更加优秀,引用,重载,命名空间,以及STL库,模板编程和更多的函数,在面向对象的编程上更加高效。C语言的优势则是更加底层,编译速度会更快,在编写内核时大多数都是C语言去写。 在C++中,命名空间(Namespace)是一种组织代码的方式,主要用于解决全局变量、函数或类的命名冲突问题。命名空间提供了一种封装机制,允许开发者将相关的类、函数、变量等放在一个逻辑上封闭的区域中,这样相同的名字在不同的命名空间中可以共存,而不会相互干扰。
122 0
|
5月前
|
C++
C++基础知识(二:引用和new delete)
引用是C++中的一种复合类型,它是某个已存在变量的别名,也就是说引用不是独立的实体,它只是为已存在的变量取了一个新名字。一旦引用被初始化为某个变量,就不能改变引用到另一个变量。引用的主要用途包括函数参数传递、操作符重载等,它可以避免复制大对象的开销,并且使得代码更加直观易读。
|
5月前
|
算法 编译器 C++
C++基础知识(三:哑元和内联函数和函数重载)
在C++编程中,"哑元"这个术语虽然不常用,但可以理解为在函数定义或调用中使用的没有实际功能、仅作为占位符的参数。这种做法多见于模板编程或者为了匹配函数签名等场景。例如,在实现某些通用算法时,可能需要一个特定数量的参数来满足编译器要求,即使在特定情况下某些参数并不参与计算,这些参数就可以被视为哑元。
101 0
|
5月前
|
C++
C++基础知识(四:类的学习)
类指的就是对同一类对象,把所有的属性都封装起来,你也可以把类看成一个高级版的结构体。
|
5月前
|
自然语言处理 程序员 C++
C++基础知识(五:运算符重载)
运算符重载是C++中的一项强大特性,它允许程序员为自定义类型(如类或结构体)重新定义标准运算符的行为,使得这些运算符能够适用于自定义类型的操作。这样做可以增强代码的可读性和表达力,使得代码更接近自然语言,同时保持了面向对象编程的封装性。
|
5月前
|
存储 编译器 C++
C++基础知识(六:继承)
多态是面向对象编程的四大基本原则之一,它让程序能够以统一的接口处理不同的对象类型,从而实现了接口与实现分离,提高了代码的灵活性和复用性。多态主要体现在两个层面:静态多态(编译时多态,如函数重载)和动态多态(运行时多态,主要通过虚函数实现)。
|
5月前
|
存储 编译器 C++
C++基础知识(七:多态)
多态是面向对象编程的四大基本原则之一,它让程序能够以统一的接口处理不同的对象类型,从而实现了接口与实现分离,提高了代码的灵活性和复用性。多态主要体现在两个层面:静态多态(编译时多态,如函数重载)和动态多态(运行时多态,主要通过虚函数实现)。
|
5月前
|
存储 算法 程序员
C++基础知识(八:STL标准库(Vectors和list))
C++ STL (Standard Template Library标准模板库) 是通用类模板和算法的集合,它提供给程序员一些标准的数据结构的实现如 queues(队列), lists(链表), 和 stacks(栈)等. STL容器的提供是为了让开发者可以更高效率的去开发,同时我们应该也需要知道他们的底层实现,这样在出现错误的时候我们才知道一些原因,才可以更好的去解决问题。
|
5月前
|
算法 前端开发 C++
C++基础知识(八:STL标准库 deque )
deque在C++的STL(Standard Template Library)中是一个非常强大的容器,它的全称是“Double-Ended Queue”,即双端队列。deque结合了数组和链表的优点,提供了在两端进行高效插入和删除操作的能力,同时保持了随机访问的特性。
|
5月前
|
存储 C++ 索引
C++基础知识(八:STL标准库 Map和multimap )
C++ 标准模板库(STL)中的 map 容器是一种非常有用的关联容器,用于存储键值对(key-value pairs)。在 map 中,每个元素都由一个键和一个值组成,其中键是唯一的,而值则可以重复。