本篇均是在菜鸟教程的C++教程中学习。
- 面向对象程序设计,四大特性:封装 继承 多态 抽象
- C++组成部分:核心语言 C++标准库 标准模板库
又说4种:C部分 面向对象部分 泛型编程 STL - 可以使用 typedef 为一个已有的类型取一个新的名字
typedef int feet;
feet name;
-
枚举
-
在函数内,局部变量的值会覆盖全局变量的值。
-
定义常量(不可更改) #define或const
-
const类型值不能被修改
volatile 告诉编译器不需要优化volatile声明的变量,让程序可以直接从内存中读取变量
restrict 修饰的指针是唯一一种访问它所指向的对象的方式。只有 C99 增加了新的类型限定符 restrict。 -
auto C++17已删除
-
register 需要快速访问的变量 变量的最大尺寸等于寄存器的大小 不能使用&运算 意味着变量可能存储在寄存器中
-
static 在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁
-
extern 用来在另一个文件中声明一个全局变量或函数。当有两个或多个文件共享相同的全局变量或函数的时候
-
位运算符:
-
向函数传递参数的方式:
指针调用:
void swap(int *x, int *y);
…
swap(&a, &b);
引用调用:(引用调用时,也会使两者数值交换)
void swap(int &x, int &y);
…
swap(a, b);
-
Lambda表达式
-
函数返回数组:返回数组名指针
-
空指针 NULL 值为0
-
指针的加减等同于数组的下标变化
-
指向指针的指针:
-
引用和指针的区别:
(1). 不存在空引用。引用必须连接到一块合法的内存。
(2). 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
(3). 引用必须在创建时被初始化。指针可以在任何时间被初始化 -
引用:
int i;
int& r=i;
i = 5;
cout << "Value of i : " << i << endl;
cout << "Value of i reference : " << r << endl;
Value of i : 5
Value of i reference : 5
- 引用作为函数的返回值
- 结构体访问成员用成员访问运算符:(.)
- 结构体作为函数参数:
void printBook( struct Books book );
…
Books Book1; // 定义结构体类型 Books 的变量 Book1
…
printBook( Book1 );
- 指向结构体的指针
struct Books *struct_pointer; //定义
…
struct_point = &Book1; //地址
…
struct_point->title; //指针访问结构的成员
- 类的定义和访问数据成员:
其中private和protected不能直接使用成员访问运算符(.)直接访问。
- 成员函数可以在类内部定义,也可以单独使用范围解析运算符(::)在类外部定义。
- 私有成员变量或函数(private)在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。(类里默认为private)
class Box{
private: double width;}
double Box::getWidth(void)
void Box::setWidth( double wid )
…
// box.width = 10.0; // Error: 因为 width 是私有的
box.setWidth(10.0); // 使用成员函数设置宽度
cout << "Width of box : " << box.getWidth() <<endl;
- protected(受保护)成员变量或函数与私有成员十分相似,但有一点不同,protected(受保护)成员在派生类(即子类)中是可访问的。
- 三种继承方式:public protected private
1.public 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中分别变成:public, protected, private //public继承访问属性不变
class B : public A{…}
2.protected 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中分别变成:protected, protected, private //protected继承,public变为protected,其余不变
class B : protected A{…}
3.private 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中分别变成:private, private, private //全都变为private
class B : private A{…}
但无论哪种继承方式,上面两点都没有改变:
1.private 成员只能被本类成员(类内)和友元访问,不能被派生类访问;
2.protected 成员可以被派生类访问。
// 基类
class Animal {
// eat() 函数
// sleep() 函数
};
//派生类
class Dog : public Animal {
// bark() 函数
};
- 一个派生类继承了所有的基类方法,除了以下几种:
- 基类的构造函数 析构函数 拷贝构造函数
- 基类的重载运算符
- 基类的友元函数
- 多继承
class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
{
<派生类类体>
};
-
函数重载:
重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。
在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数。 -
运算符重载
Box operator+(const Box&,const Box&);
例:
class Box {…
Box operator+(const Box& b) {
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box; }
…
Box Box1; // 声明 Box1,类型为 Box
Box Box2; // 声明 Box2,类型为 Box
Box Box3; // 声明 Box3,类型为 Box
…
Box3 = Box1 + Box2;
…
- 下面是可重载的运算符列表:
下面是不可重载的运算符列表:
.:成员访问运算符
., ->:成员指针访问运算符
:::域运算符
sizeof:长度运算符
?::条件运算符
#: 预处理符号
- 运算符重载的举例C++ 重载运算符和重载函数 | 菜鸟教程 (runoob.com)
- 多态:当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。
多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。
class Shape {
public:
int area() {
cout << "Parent class area :" <<endl;
return 0; }
};
class Rectangle: public Shape{
public:
int area () {
cout << "Rectangle class area :" <<endl;
return (width * height); }
};
class Triangle: public Shape{
public:
int area () {
cout << "Triangle class area :" <<endl;
return (width * height / 2); }
};
…
int main( ) {
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5); // 存储矩形的地址 构造函数省略
shape = &rec; // 调用矩形的求面积函数 area
shape->area(); // 存储三角形的地址
shape = &tri; // 调用三角形的求面积函数 area
shape->area();
return 0;
}
产生结果如下:
Parent class area :
Parent class area :
调用函数 area() 被编译器设置为基类中的版本,这就是所谓的静态多态,或静态链接 - 函数调用在程序执行前就准备好了。有时候这也被称为早绑定,因为 area() 函数在程序编译期间就已经设置好了。
修改:
在基类中area()的声明前放置关键词virtual
virtual int area() {
cout << "Parent class area :" <<endl;
return 0;
}
结果如下:
Rectangle class area :
Triangle class area :
每个子类都有一个函数 area() 的独立实现。这就是多态的一般使用方式。有了多态,您可以有多个不同的类,都带有同一个名称但具有不同实现的函数,函数的参数甚至可以是相同的。
-
虚函数
virtual修饰符则强调父类的成员函数可以在子类中被重写,因为重写之时并没有与父类发生任何的调用关系,故而重写是被允许的。
虚函数 是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定。
纯虚函数:改写为 virtual int area() = 0; 告诉编译器,函数没有主体,是纯虚函数。以便在派生类中重新定义该函数更好地适用于对象,但是您在基类中又不能对虚函数给出有意义的实现。 -
数据抽象:只向外界提供关键信息,并隐藏其后台的实现细节,即只表现必要的信息而不呈现细节。(数据私有化,仅提供对外调用的接口)
优势:1. 类的内部受到保护,不会因无意的用户级错误导致对象状态受损。2. 类实现可能随着时间的推移而发生变化,以便应对不断变化的需求,或者应对那些要求不改变用户级代码的错误报告。 -
数据封装是一种把数据和操作数据的函数捆绑在一起的机制,数据抽象是一种仅向用户暴露接口而把具体的实现细节隐藏起来的机制。
通常情况下,我们都会设置类成员状态为私有(private),除非我们真的需要将其暴露,这样才能保证良好的封装性。这通常应用于数据成员,但它同样适用于所有成员,包括虚函数。 -
接口设计:面向对象的系统可能会使用一个抽象基类为所有的外部应用程序提供一个适当的、通用的、标准化的接口。然后,派生类通过继承抽象基类,就把所有类似的操作都继承下来。