打开C++的大门
Posted Ricky_0528
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了打开C++的大门相关的知识,希望对你有一定的参考价值。
初识C++
1.C++的三大特性(背)
①封装
把客观的事务抽象成一个类(将数据和方法打包在一起,加以权限的区分,达到保护并安全使用数据的目的)
②继承
继承所表达的是类之间相关的关系,这种关系使得对象可以继承另外一类对象的特征和能力 -> 避免公用代码的重复开发,减少代码和数据冗余
③多态
多态性可以简单地概括为“一个接口,多种方法”,字面意思为多种形态。程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念
2.C与C++的区别
C面向过程:
核心:功能分解,自顶向下,逐层细化(程序=数据结构+算法)
C++面向对象:
在面向对象中,算法与数据结构被看做是一个整体,称作对象(对象=算法+数据结构)
3.C++命名空间
①:: 作用域运算符
#include<iostream>
int a=100;
int main()
{
int a=10;
std::cout<<"局部变量a="<<a<<std::endl;
std::cout<<"全局变量a="<<::a<<std::endl;//这里::取全局变量
std::cin.get();
}
②namespace解决命名冲突
a.命名空间只能全局范围内定义
b.命名空间可以嵌套命名空间
c.命名空间是开放的,可以随时把新的成员加入已有的命名空间中
d.命名空间中的函数,可以在命名空间外定义
e.无名命名空间,其命名空间的标识符只能在本文件访问
f.命名空间可以取别名
#include<iostream>
namespace A
{
int a=100;
void func(int n);
}
void A::func(int n)
{
for(int i=0;i<n;i++)
std::cout<<i<<' '<<std::endl;//命名空间中的函数,可以在命名空间外定义
}
namespace B
{
int a=10;
namespace C
{
int a=1;//命名空间可以嵌套命名空间
}
}
namespace A
{
int b=666;//命名空间是开放的,可以随时把新的成员加入已有的命名空间中
}
int main()
{
namespace sp=A;//命名空间可以取别名
std::cout<<"A中a="<<A::a<<std::endl;
std::cout<<"A中b="<<A::b<<std::endl;
std::cout<<"B中a="<<B::a<<std::endl;
std::cout<<"B中C中a="<<B::C::a<<std::endl;
A::func(10);
std::cin.get();
}
③using使用命名空间
a.会先从命名空间中寻找变量、函数,找不到再从其他地方找
b.局部变量优先
#include<iostream>
namespace A
{
int a=10;
}
//using namespace A; //全局使用整个命名空间
int main()
{
int a=100;
// using A::a;//using直接使用命名空间内的变量会与局部变量冲突
using namespace A;
std::cout<<a;//会优先使用局部变量
std::cin.get();
}
4.C++中几个增强
①语法检查增强
a.变量不能重复定义
b.所有变量与函数必须要有类型
c.不同类型的变量不能直接赋值,需要相对应的强转
②结构体增强
a.结构体中可以定义成员函数
b.创建变量无需加struct关键字
#include<iostream>
struct test
{
int a=10;
void Output_num(void)//定义成员函数
{
std::cout<<a<<std::endl;
}
};
int main()
{
test a;//无需struct
a.Output_num();
std::cin.get();
}
③新增bool类型
标准C++的bool类型有两种内建的常量true(转换为整数1)和false(转换为整数0)表示状态,它们都为关键字。bool类型只有两个值,占1个字节大小。给bool类型赋值时,非0值会自动转换为true(1),0值会自动转换为false(0)
④三目运算符功能增强
C++中三目运算表达式返回值为变量本身的引用,可以赋值
5.C/C++中的const
C语言中(默认为外部链接)
①const修饰全局变量,变量名只读,内存空间在文字常量区(只读),因此不能通过地址来修改空间内容
②const修饰局部变量,变量名只读,内存空间在栈区(可读可写),可以通过地址间接的修改空间内容
C++中(默认为内部链接)
①对于基础类型,用const修饰编译器会把它放入符号表中
②对其取地址,系统才会给data开辟空间
③若用变量名对const修饰的变量赋初值,系统会为其直接开辟空间
④对于自定义数据类型(结构体、对象等),用const修饰系统会给其开辟空间
⑤若要转换为外部链接,要在定义处加上extern
#include<iostream>
int main()
{
const int data = 10;//放入符号表
std::cout << "data = " << data << std::endl;
int *p = (int *) &data;//取地址系统才会给其开辟空间
*p = 20;
std::cout << "*p = " << *p << std::endl;
std::cout << "data = " << data << std::endl;//原先的值并不会改变
int b = 100;
const int a = b;//此时a不会放入符号表中,系统会直接为其开辟空间
std::cout << "a = " << a << std::endl;
p = (int *)&a;
*p = 200;
std::cout << "*p = " << *p << std::endl;
std::cout << "a = " << a << std::endl;//原先的值也会跟着一起改变
std::cin.get();
}
⭐️尽量用const替换#define
①const有类型,可进行编译器类型安全检查。#define无类型,不可进行类型检查
②const有作用域,而#define不重视作用域,默认定义处到文件结尾。如果定义在指定作用域下有效的常量,那么#define就不能用
③宏不能作为命名空间的成员,const可以
6.引用(给变量取别名)
引用必须初始化且一旦初始化就不能再修改别名
①作用于数组
#include<iostream>
int main()
{
//法1
int arr[5]={1,2,3,4,5};
int (&my_arr)[5]=arr;//[]优先级高于& 若不加括号则先与[]结合 b为一个数组里面的元素均为引用
for(int i=0;i<5;i++)
std::cout<<my_arr[i]<<' ';
//法2
typedef int TYPE_ARR[5];//TYPE_ARR就是一个数组类型(有5个元素,每个元素为int)
TYPE_ARR &myArr=arr;//TYPE_ARR=int [5]
for(int i=0;i<5;i++)
std::cout<<myArr[i]<<' ';
std::cin.get();
}
②作为函数参数
#include<iostream>
void Swap(int &a,int &b)
{
int tmp=a;
a=b;
b=tmp;
}
int main()
{
int x=5,y=10;
std::cout<<x<<' '<<y<<std::endl;
Swap(x,y);//直接传值即可
std::cout<<x<<' '<<y<<std::endl;
std::cin.get();
}
③作为函数返回值
a.函数返回值为引用时,不要返回局部变量
b.当函数返回值作为左值,函数的返回值类型必须是引用(多用于运算符重载)
#include<iostream>
int& My_data(void)
{
static int num=200;
std::cout<<"num = "<<num<<std::endl;
return num;//函数返回什么变量,引用就是该变量的别名
}
int main()
{
int &ret=My_data();
std::cout<<"ret = "<<ret<<std::endl;
My_data()=2000;//函数返回值作为左值
My_data();
std::cin.get();
}
④引用的本质
引用在C++内部是一个指针常量,Type& ref=val == Type* const ref = &val;
⑤指针的引用
#include<iostream>
#include<cstdlib>
#include<cstring>
void MyStr1(char **p_str) //p_str=&str 即 *p_str=str
{//对*p_str操作就相当于对str操作
*p_str=(char *) calloc(1,sizeof (char));
strcpy(*p_str,"hello world");
}
void MyStr2(char* &my_str)//&my_str = str2 my_str为str2的一个别名 str2的定义为char* 又&my_str=str2 故形参定义为...
{
my_str=(char *) calloc(1,sizeof(char));
strcpy(my_str,"hello world");
}
int main()
{
//任务:封装一个函数 从堆区给str申请一个空间 并赋值为“hello world”
char *str1=nullptr;
MyStr1(&str1);//在函数内部更改指针指向,要传地址进去
std::cout<<"str1 = "<<str1<<std::endl;
free(str1);
char *str2=nullptr;
MyStr2(str2);
std::cout<<"str2 = "<<str2<<std::endl;
free(str2);
std::cin.get();
}
函数参数变成指针的引用,不用取得指针的地址
⑥常引用
引用传参不会开辟新的空间,常引用在降低开销的同时,也能防止被修改
#include<iostream>
typedef struct
{
int num;
char name[10];
}STU;
void PrintStruct(const STU &tmp)//tmp即为常引用
{//这里只有读取操作,故用const修饰,防止被修改
std::cout<<"学号:"<<tmp.num<<" 姓名:"<<tmp.name<<std::endl;
}
int main()
{
STU s1={2020135,"Ricky"};
PrintStruct(s1);
std::cin.get();
}
常量的引用 应不能被修改 故要用const修饰
const int &num=10;
7. 内联函数(inline function)
保持预处理宏的效率又增加安全性,而且可以像一般成员函数那样可以在类里访问自如
内联函数为了继承宏函数的效率,没有函数调用时的开销。然后又可以像普通函数那样,可以进行参数、返回值类型的安全检查,又可以作为成员函数
是一个真正的函数,函数的替换发生在编译阶段
#include<iostream>
inline int My_mul(int x,int y)
{
return x*y;
}
int main()
{
std::cout<<My_mul(10+10,20+20)<<std::endl;
std::cin.get();
}
⭐️在类内部定义的函数会自动成为内联函数,不需要加inline关键字
内联函数的条件(加inline仅仅是给编译器一个建议):
- 不能存在任何形式的循环语句
- 不能存在过多的条件判断语句
- 函数体不能过于庞大
- 不能对函数进行取址操作
8.默认(缺省)参数
声明函数原型时可为一个或多个参数指定默认的参数值,当函数调用的时候如果没有传递该参数值,编译器会自动用默认值替代
#include<iostream>
int Add(int x=10,int y=20)
{
return x+y;
}
int main()
{
std::cout<<Add(100,200)<<std::endl;
std::cout<<Add(100)<<std::endl;
std::cout<<Add()<<std::endl;
std::cin.get();
}
注意:
-
函数的默认参数从左向右,如果一个参数设置了默认参数,那么这个参数之后的参数都必须设置默认参数
-
如果函数声明和函数定义分开写,函数声明和函数定义不能同时设置默认参数,定义处的默认参数时无效的
建议在函数声明处设置默认参数
9.占位参数
占位参数只有参数类型声明,而没有参数名声明
调用函数时必须给占位参数传参,但不能再函数内使用
10.函数重载(多态的特性)
定义:
同一个函数名在不同场景下可以具有不同的含义
意义:
方便的使用函数名
条件:
同一个作用域 参数个数不同 参数类型不同 参数顺序不同
注意:
- 函数的返回值类型不能作为函数重载的依据
- 函数重载和默认参数一起使用,需要额外注意二义性问题
#include<iostream>
int Add(int x,int y=20)
{
std::cout<<"int int的Add"<<std::endl;
}
int Add(int x)
{
std::cout<<"int的Add"<<std::endl;
}
int main()
{
Add(10);//产生二义性,两个Add都能识别
std::cin.get();
}
11.C++和C混合编程
fun.h
#ifndef FUN_H
#define FUN_H
#if __cplusplus
extern "C"{
#endif
int Add(int x,int y);
int Sub(int x,int y);
#if __cplusplus
};
#endif
#endif //FUN_H
fun.c
#include<stdio.h>
int Add(int x,int y)
{
return x+y;
}
int Sub(int x,int y)
{
return x-y;
}
main.cpp
#include<iostream>
#include"fun.h"
int main()
{
std::cout<<Add(100,200)<<std::endl;
std::cout<<Sub(100,200)<<std::endl;
std::cin.get();
}
以上是关于打开C++的大门的主要内容,如果未能解决你的问题,请参考以下文章