面向对象的四大特征
- 封装(Encapsulation):封装是将数据和方法组合在一起,对外部隐藏实现细节,只公开对外提供的接口。这样可以提高安全性、可靠性和灵活性。
- 继承(Inheritance):继承是从已有类中派生出新类,新类具有已有类的属性和方法,并且可以扩展或修改这些属性和方法。这样可以提高代码的复用性和可扩展性。
- 多态(Polymorphism):多态是指同一种操作作用于不同的对象,可以有不同的解释和实现。它可以通过接口或继承实现,可以提高代码的灵活性和可读性。
- 抽象(Abstraction):抽象是从具体的实例中提取共同的特征,形成抽象类或接口,以便于代码的复用和扩展。抽象类和接口可以让程序员专注于高层次的设计和业务逻辑,而不必关注底层的实现细节。
标准库
- 标准的 C++ 由三个重要部分组成:
- 核心语言,提供了所有构件块,包括变量、数据类型和常量,等等。
- C++ 标准库,提供了大量的函数,用于操作文件、字符串等。
- 标准模板库(STL),提供了大量的方法,用于操作数据结构等。
命名空间
1.命名空间是为了解决多人合作取标识符时的重命名的问题
2.什么是命名空间
//命名空间
namespace A { // A是空间的名字
int a;
void func()
{
}
}
3.命名空间的注意
注意1:命名空间只能写在全局
注意2:命名空间可以嵌套命名空间
//命名空间可以嵌套命名空间
namespace Maker
{
int a;
namespace B
{
int b;
}
}
注意3:命名空间是开放的,随之可以加入新成员,但是新成员你只能在加入后使用
namespace Maker
{
int a;
namespace B
{
int b;
}
}
namespace Maker
{
int c;
}(注:这两个Maker命名空间是表示的是同一个)
注意4:匿名命名空间
//类似于static int d = 50
namespace
{
int d = 50;
}
注意5:命名空间取别名
//命名空间取别名
void test01()
{
namespace nameMaker = Maker;
cout << nameMaker::a << endl;
}
注意6:分文件编写代码时,如果.h中有两个命名空间,但里面的成员函数或成员变量同名,在.cpp中实现函数时则需加上命名空间
test.h头文件
#pragma once
#include<iostream>
using namespace std;
namespace myMaker1
{
void func();
}
namespace myMaker2
{
void func();
}
test.cpp文件
#include "test.h"
void myMaker1::func()
{
cout << "func" << endl;
}
4.作用域运算符(::)
用来访问某个作用域里面的成员
namespace Maker
{
int a;
namespace B
{
int b = 40;
}
}
namespace Maker
{
int c = 30;//可以相当于限制在括号中的全局变量
}
int ma = 10;
int main()
{
int ma = 20;
//就近原则
cout << "ma = " << ma << endl;
cout << "::ma =" << ::ma << endl;
cout << "Maker范围内 = " << Maker::c << endl;
cout << Maker::B::b << endl;
return 0;
}
using声明和编译指令
using声明是让命名空间中某个标识符可以直接使用
namespace A
{
int a = 10;
int b = 20;
int c = 30;
}
void test01()
{
//usin声明是让命名空间中某个标识符可以直接使用
using A::a;
cout << a << endl;
}
using编译指令,让某个命名空间中的标识符都可以直接使用
void test02()
{
//using编译指令,让某个命名空间中的标识符都可以直接使用
using namespace A;
cout << a << endl;
cout << b << endl;
cout << c << endl;
int a = 100;//类似于命名空间中的啊是全局变量,这里的a是局部变量
cout << "a = " << a << endl;
}
注意:1.在一个程序中,变量只能定义一次,却可以声明多次。
2.定义分配存储空间,而声明不会。
结构体的加强
加强一:定义变量时不需要使用struct
//自定义数据类型
struct MyStruct
{
char name[64];
int age;
};
void test01()
{
MyStruct a;//不需要加struct就可以定义变量
}
加强二:结构体内可以写函数
struct MyStruct1
{
int a;
void func()
{
cout << "func" << endl;
}
};
void test02()
{
MyStruct1 a1;
a1.func();
}
更严格的类型转换
不能进行隐式转换,必须显示的转换
三目运算符
c语言的三目运算符返回的是右值
c++的三目运算符返回的是左值,是空间
左值和右值的概念
在c++中可以放在赋值操作符左边的是左值,可以放在赋值操作符右边的是右值
有些变量既可以当左值也可以当右值
左值为Lvalue,L表示Location,表示内存可以寻址,可以赋值
右值为Rvalue,R表示Read,就是可以知道它的值
const常量
const是一个限定符,它用来限定一个变量不允许改变,它将一个对象转换成一个常量
1.c语言的const修饰的变量都有空间
2.c语言的const修饰的全局变量具有外部链接属性
3.c++语言的const修饰的变量有时有空间,有时无空间(发生常量折叠,且未对变量进行取址操作)
const int aa = 10;//没有内存
void test()
{
//发生了常量折叠
cout << "aa = " << aa << endl;//在编译阶段, 编译器优化为:cout << "aa=" << 10 <<endl;
const int bb = 20;//栈区
//volatile禁止优化
//volatile const int bb = 20;
int* p = (int*)&bb;//进行了取址操作,所以有空间
*p = 200;
cout << "bb = " << bb << endl;//编译器优化了
cout << "*p = " << *p << endl;
cout << "a的地址:" << &bb << endl;
cout << "p指向的地址:" << p << endl;
}
4.c++语言中的const修饰的全局变量具有内部链接属性
extern const int cc = 300;//加上extern就变为内部链接属性
5.c++编译器不能优化的情况
- 自定义数据类型
- 用变量给const修饰的局部变量赋值
- 编译器是在编译阶段对数据进行优化
6.尽量用const代替define
- define没有数据类型,const修饰的变量有数据类型,可以进行数据类型检查
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#define MA 15
const short ma = 10;
void Myfun(short data)
{
cout << "Myfun(short data)" << endl;
}
void Myfun(int data)
{
cout << "Myfun(int data)" << endl;
}
int main()
{
Myfun(MA);
Myfun(ma);
return 0;
}
- const修饰的变量有作用域,define不重视作用域,不能限定常量的使用范围
引用(重点)
引用是c++对c 的重要扩充。在c/c++中指针的作用基本都是一样的,但是c++增加了另外一种给函数传递地址的途径,这就是按引用传递,它也存在于其他一些编程语言中,并不是c++的发明
- 引用的作用:与c语言的指针一样的功能,并且能是语法更加简洁
- 引用是什么:引用相当于给空间取别名
- 引用的语法
void func(int& a) // int &a = a;
{
a = 200;
}
void test02()
{
int a = 10;
func(a);
cout << "a = " << a << endl;
}
- 引用的注意
注意1:int& b = a; 这里的&不是取地址操作符,是引用的标记作用
注意2:引用创建时,必须初始化
注意3:引用一旦初始化就不能改变它的指向
注意4:引用必须引用一块合法的内存空间
- 数组的引用
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
int main()
{
int arr[] = { 1,2,3,4,5 };
//第一种方法
//1.定义数组类型
typedef int(MY_ARR)[5];
//2.建立引用
MY_ARR& p1 = arr;//建立引用,int &b =a;
//第二种方法
//直接定义引用
int(&p2)[5] = arr; // int &b =a;
//第三种方法
typedef int(&MY_ARR1)[5];// 建立引用数组类型
MY_ARR1 p3 = arr;
for (int i = 0; i < 5; i++)
{
cout << p1[i] << ',';
cout << p2[i] << ',';
cout << p3[i] << endl;
}
return 0;
}
- 引用的本质
引用的本质:C++中,引用的内部实现是一个指针常量。全部的指针操作由编译器自动转换。
(1)指针常量的指针指向不可变 → 引用初始化后不可更改
(2)指针常量指向的值可以改变 → 引用对应的数据可重新赋值
//发现是引用,转化为 int* const p = &a;
void testFunc(int& p){
p =100;// p 是引用,转化为*p =100;
}
int main() {
int a = 10;
int& ref = a; //编译器内部自动转换为 int * const ref = &a;这也说明引用为什么必须初始化
ref = 20; //编译器内部自动转换为 *ref = 20;
cout << "a:" << a << endl;
cout << "ref:" << ref << endl;
//引用作为函数参数传递
testFunc(a); //编译器内部自动转换为 int * const ref = &a;
cout << "a:" << a << endl;
cout << "ref:" << ref << endl;
return 0;
}
指针的引用(重点)
指针的引用是给指针变量这块空间取别名
void test()
{
char a = 'm';
char* p = &a;
char*& p1 = p;
/*int a = 1;
int* p = &a;
int*& p1 = p;*/
cout << *p1 << endl;
}
//被调函数
void func(char* &tmp)
{
char* tp;
tp = (char*)malloc(64);
memset(tp, 0, 64);
strcpy(tp, "笑话");
tmp = tp;
}
//主调函数
void test1()
{
char* mp = NULL;
func(mp);
cout << mp << endl;
}
c和c++的区别
- c语言的结构体不能写函数,c++可以
- 结构体定义变量时,c++不需要加struct关键字
- 更加严格的类型检查
- const修饰的变量,c++有事没有内存,c语言的都有内存
- 三目运算符返回的值不一样
- 引用和c语言的指针功能一样