c++对c的扩展

面向对象与面向过程

面向过程:以过程为核心,强调**事件的流程、顺序,**如:C语言

面向过程是一种以过程为中心的编程思想。 通过分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。 面向过程编程思想的核心:功能分解,自顶向下,逐层细化(程序=数据结构+算法)。

面向对象:以对象为核心,强调**事件的角色、主体,**如:C++

在面向对象中,算法与数据结构被看做是一个整体,称作对象,现实世界中任何类的对象都具有一定的属性和操作,也总能用数据结构与算法两者合一地来描述,所以可以用下面的等式来定义对象和程序:对象 = 算法 + 数据结构 程序 = 对象 + 对象 + ……程序就是许多对象在计算机中相继表现自己,而对象则是一个个程序实体。 面向对象编程思想的核心:应对变化,提高复用。

面向对象的三大特点

封装 把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。 类将成员变量和成员函数封装在类的内部,根据需要设置访问权限,通过成员函数管理内部状态。
继承 继承所表达的是类之间相关的关系,这种关系使得对象可以继承另外一类对象的特征和能力。 继承的作用:避免公用代码的重复开发,减少代码和数据冗余。
多态 多态性可以简单地概括为“一个接口,多种方法”,字面意思为多种形态。程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。

::作用域运算符

::解决归属问题

#include<iostream>
using namespace std;
int data=100;
int main()
{
    int data=10;
    cout<<data<<endl;//10,局部变量
    cout<<::data<<endl;//100,全局变量
    return 0;
}

C++命名空间(namespace)

在c++中,名称(name)可以是符号常量、变量、函数、结构、枚举、类和对象等等,标准C++引入关键字
namespace(命名空间/名字空间/名称空间)为了避免使用多个厂商的类库时,可能导致名称冲突问题。

#include<iostream>
using namespace std;
namespace A {   //创建一个命名空间
int a=10;
}
namespace B {  //命名空间只能全局范围内定义
int b=100;
namespace C {   //命名空间可嵌套命名空间
int c=200;
}
}
namespace A {   //命名空间是开放的,即可以随时把新的成员加入已有的命名空间中,注意名字不能重复
int d=300;
}
int main()
{   namespace E=A;    //给namespace A取别名E,原来的名字A也可以用
    cout<<A::a<<"\t"<<B::b<<"\t"<<B::C::c<<endl;
    cout<<E::d<<endl;
    return 0;
}

无名的namespace

意味着命名空间中的标识符只能在本文件内访问,相当于给这个标识符加上了static,使得其可以作为内部连接

#include<iostream>
using namespace std;
namespace{
int a = 10;
void func(){ cout << "hello namespace" << endl; }
}
int main(){
cout << "a : " << a << endl;
func();
}

函数声明和定义的分离

#include<iostream>
using namespace std;
namespace MySpace{  //在namespace中声明函数
void func1();
void func2(int num);
}
void MySpace::func1(){      //定义函数的时候一定要函数的作用域MySpace::func1()
cout << "MySpace::func1" << endl;
}
void MySpace::func2(int num){
cout << "MySpace::func2 : " << num << endl;
}
int main(){
   MySpace::func1();    //调用函数的时候也要说明函数的作用域
   MySpace::func2(10);
}

using声明 命名空间中的成员 可用

#include<iostream>
using namespace std;

namespace A{
int numA = 20;
void funcA(){ cout << "hello funcA" << endl; }
}

int main(){
    cout << A::numA << endl;//不可直接访问,通过命名空间域运算符
    A::funcA();
    //funcA();err,
    using A::funcA;//using声明成员可用,就可以直接访问了
    using A::numA;
    cout << numA << endl;
    funcA();
}

using声明成员碰到函数重载

如果命名空间包含一组用相同名字重载的函数,using声明就声明了这个重载函数的所有集合。

#include<iostream>
using namespace std;
namespace A{
void func(){cout<<0<<endl;}
void func(int x){cout<<x<<endl;}
int func(int x,int y){cout<<x+y<<endl;return 0;}
}
int main(){
using A::func;
func();
func(10);
func(10, 20);
}

using 声明整个命名空间可用

namespace	A{
    ...
}
int main(){
    using namespase A;
    ...
}

使用using声明或using编译指令会增加命名冲突的可能性。也就是说,如果有名称空间,并在代码中使用作用域解析运算符,则不会出现二义性。

struct类型增强

结构体中即可以定义成员变量,也可以定义成员函数,c++中定义结构体变量不需要加struct关键字.

#include<iostream>
using namespace std;

struct Student{
string mName;     //定义成员变量  
int mAge;           //定义成员变量 
void setName(string name){ mName = name; }      //定义成员函数
void setAge(int age){ mAge = age; }             //定义成员函数       
void showStudent(){                             //定义成员函数
cout << "Name:" << mName << " Age:" << mAge << endl;
}
};
int main(){
    Student student;      //定义结构体变量
    student.setName("John");
    student.setAge(20);
    student.showStudent();;
}

bool类型关键字

标准c++的bool类型有两种内建的常量true(转换为整数1)和false(转换为整数0)表示状态。这三个名字都是关键字。 bool类型只有两个值,true(1值),false(0值) bool类型占1个字节大小 给bool类型赋值时,非0值会自动转换为true(1),0值会自动转换false(0)

#include<iostream>
using namespace std;

int main(){
    bool a=100;
    bool b=true;
    bool c=0;
    bool d=false;
    cout<<a<<"  "<<b<<"  "<<c<<"  "<<d<<endl;//1  1  0   0
}

引用(reference)

引用的本质:就是给变量名取个别名。

#include<iostream>
using namespace std;
void test(int& a)//引用作为函数的形参,
{a=101;}            //函数内部可以 通过 引用 操作外部变量
int main(){
    int a=0;
    int &b=a;     //&修饰变量为引用 b就是a的别名(引用),系统不会为引用 开辟空间,a和b代表同一空间内容,引用必须初始化
    b=100;          //操作b等价操作a
    cout<<a<<endl;//100
    int arr[2]={1,2};
    int (&brr)[2]=arr;//数组的引用
    brr[1]=4;
    cout<<arr[1]<<endl;
    int *p=&a;
    int* (&q)=p;   //指针变量的引用
    cout<<*p<<endl;
    cout<<*q<<endl;
    void (&fun)(int& a)=test;  //函数的引用
    int num1=100;
    int &nm1=num1;//普通变量的引用
    fun(nm1);//引用作为函数的实参
    cout<<num1<<endl;
}

引用的语法更清楚简单:

  1. 函数调用时传递的实参不必加“&”符
  2. 在被调函数中不必在参数前加“*”符 引用作为其它变量的别名而存在,因此在一些场合可以代替指针。
  3. C++主张用引用传递取代地址传递的方式,因为引用语法容易且不易出错。

引用作为函数的返回值类型

不要返回普通局部变量的引用

返回值类型为引用 可以完成链式操作

#include<iostream>
using namespace std;
struct Stu
{
Stu& printStu(Stu &ob, int value)
{
cout<<value<<" ";
return ob;
}
};
int main()
{
Stu ob1;
ob1.printStu(ob1, 100).printStu(ob1, 200).printStu(ob1, 300);//100 200 300
}

常引用

给常量取别名,不能通过常引用 修改 内容。

//int &a = 10;//err
const int &a = 10;//a就是10的别名
//a=100;//err
cout<<a<<endl;//10

常引用 作为函数的参数:防止函数内部修改外部的值。

void printInt(const int &a)
{
//a = 200;//err
cout<<"a = "<<a<<endl;
}
int main()
{
int num = 100;
printInt(num);//a = 100
}

内联函数

内联函数 必须在定义的时候 使用关键字inline修饰, 不能在声明的时候使用inline

//函數声明的时候 不要使用inline
int myAdd(int x, int y);
int main()
{
cout<<myAdd(100,200)<<endl;
}
//内联函数 在定义的时候使用inline
inline int myAdd(int x, int y)
{
return x+y;
}

内联函数:在编译阶段 将内联函数中的函数体 替换函数调用处。避免函数调用时的开销。

宏函数和内联函数的区别

宏函数和内联函数 都会在适当的位置 进行展开 避免函数调用开销。

宏函数在预处理阶段展开
内联函数在编译阶段展开

宏函数的参数没有类型,不能保证参数的完整性。
内联函数的参数有类型 能保证参数的完整性

宏函数没有作用域的限制,不能作为命名空间、结构体、类的成员
内联函数有作用域的限制,能作为命名空间、结构体、类的成员

内联函数的注意事项

在内联函数定义的时候加inline修饰
类中的成员函数 默认都是内联函数(不加inline 也是内联函数)
有时候 就算加上inline也不一定是内联函数(内联函数条件)
不能存在任何形式的循环语句
不能存在过多的条件判断语句
函数体不能过于庞大
不能对函数取地址
有时候不加inline修饰 也有可能是内联函数。
内不内联 由编译器决定。

函数重载

函数重载 是c++的多态的特性(静态多态)。

函数重载:用同一个函数名 代表不同的函数功能。

函数重载的条件

同一作用域,函数的参数类型不同、个数不同、顺序不同 都可以重载。(返回值类型不能作为重载的条件)

void printFun(int a)
{
cout<<"int"<<endl;
}
void printFun(int a, char b)
{
cout<<"int char"<<endl;
}
void printFun(char a, int b)
{
cout<<"char int"<<endl;
}
void printFun(char a)
{
cout<<"char"<<endl;
}
int main()
{
printFun(10);//int
printFun(10, 'a');//int char
printFun('a', 10);//char int
printFun('a');//char
}

函数重载的底层实现原理:函数在编译器下生成的编译之后的函数名不同;

void func(){}
void func(int x){}
void func(int x,char y){}
//编译后的名字可能是
_Z4funcv //v 代表void,无参数
_Z4funci //i 代表参数为int类型c
_Z4funcic //i 代表第一个参数为int类型,第二个参数为char类型

函数的默认参数

c++在声明函数原型的时可为一个或者多个参数指定默认(缺省)的参数值,当函数调用的时候如果没有指定这个值,编译器会自动用默认值代替。

void Test01(int a = 10, int b = 20){
cout << a + b << endl;
}
void Test02(int a,int b = 10,int c = 10){} //形参b设置默认参数值,那么后面的形参c也需要设置默认参数
void Test03(int a = 0,int b = 0);//如果函数声明和函数定义分开,函数声明设置了默认参数,函数定义不能再设置默认参数
void Test03(int a, int b){
}
int main(){
Test01();//如果没有传参数,那么使用默认参数,10和20
Test01(100);//如果传一个参数,那么第二个参数使用默认参数,100和20
Test01(100, 200);//如果传入两个参数,那么两个参数都使用我们传入的参数100和200
return 0;
}

默认参数和函数重载同时出现 一定要注意二义性

void func(int x);
void func(int x,int y=10);
//此时func都可以只传入一个int实参,所以传入一个int实参时会产生歧义
func(10,20);//ok
func(10);//err 产生二义性

占位参数

c++在声明函数时,可以设置占位参数。占位参数只有参数类型,而没有参数名。一般情况下,在函数
体内部无法使用占位参数。

void TestFunc01(int a,int b,int){  //没有函数名,函数内部无法使用占位参数
cout << "a + b = " << a + b << endl;
}
void TestFunc02(int a, int b, int = 20){  //占位参数也可以设置默认值20
cout << "a + b = " << a + b << endl;
}
int main(){
//TestFunc01(10,20);错误调用,占位参数也是参数,必须传指定类型的参数
TestFunc01(10,20,30);//正确调用
TestFunc02(10,20);//正确调用,
TestFunc02(10, 20, 30);//正确调用
return 0;
}

extern “C” 浅析

extern "C"的主要作用就是为了实现c++代码能够调用其他c语言代码。加上extern "C"后,这部分代码编译器按c语言的方式进行编译和链接,而不是按c++的方式。

fun.h 头文件

#ifndef MYMODULE_H
#define MYMODULE_H    //防止头文件重复包含
#include<stdio.h>
#if __cplusplus       //c++
extern "C"{           //告诉编译器这部分代码按c语言的方式进行编译和链接
#endif
extern void func1();
extern int func2(int a,int b);
#if __cplusplus
}
#endif
#endif

fun.c 函数的源文件

#include<stdio.h>
#include"fun.h"
void func1(){
printf("hello world!");
}
int func2(int a, int b){
return a + b;
}

main.cpp c++的源文件

#include<iostream>
#include "fun.h"
using namespace std;
int main(){
func1();
cout << func2(10, 20) << endl;
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值