C++学习02

一. c++中的引用

引用: 给一个已知的变量起一个别的名字,内存不会为其分配新的内存地址  ---- 节省内存空间

1.语法

数据类型   &引用名 = 引用的变量名

C++
int a = 10;
int &b = a;   // 此时的a和b是完全等价
//定义函数 交换两个变量的值
void swap1(int m,int n){
    cout << "交换前mn的结果:" << m << ":" << n << endl;
    int tmp = m;
    m = n;
    n = tmp;
    cout << "交换后mn的结果:" << m << ":" << n << endl;
}

//定义函数 交换两个变量的值--参数是指针类型
void swap2(int * m,int * n){
    int tmp = *m;
    *m = *n;
    *n = tmp;
}
//定义函数 交换两个变量的值--参数是引用类型
void swap3(int &m,int &n){
   int tmp = m;
   m = n;
   n = tmp;

}

2.使用引用传参数好处

在传参过程中,不会分配新的变量空间----节省内存空间

使用场景: 一般用在函数传参中,让函数直接访问数据本身

3.常量引用

1.语法

const 数据类型 &引用变量名 = 引用的对象

举例:

C++
int a = 12345;
// 常量引用
const int &b = a;
// b 无法修改 a的值

2.作用

1 防止引用名修改原来变量的值(防止原来的数据被修改)

2 对数据常量进行引用

4.常量引用作为函数的参数

当引用作为参数传递时, 用户不需要修改该数据时, 传递常量引用

C++
// 定义函数 传递引用参数  -- 数据不需要修改  常量引用

int add(const int &m,const int &n){
    return m + n;
}

int main(int argc, char const *argv[])
{
 
int a = 40 ;
    int b = 20;  

   cout << add(a,b) << endl;   //既可以传递变量
   cout << add(100,200) << endl; //也可以传递常量
 }

补充:

常量引用的特殊用法:  

数据类型  &&引用名 =  引用的对象;  

举例:

C++
int   &&a = 1000;   //只能引用常量 不能引用变量
//特殊用法--&& 只能引用常量 不能引用变量
int sub(int &&x, int &&y){
    return x - y;
}

int main(int argc, char const *argv[])
{
    //cout <<sub(a,b) <<endl;   //不能引用变量
   cout <<sub(34,23) <<endl;   //只能引用常量
}

5.引用作为函数的返回值

注意: 使用引用作为函数的返回值, 必须要保证函数结束之后, 引用对象的空间必须存在!!

C++
//2 定义全局变量
// int sum = 10086;
//定义函数
// 引用作为函数返回值使用
int &add(){

    // int sum = 10086;
            // sum局部变量 函数执行结束 会被系统回收
            // 引用时 sum已经被系统释放了 所以不能作为引用对象

    //解决:将返回值从栈空间转为数据段存储
    //1. static 修改为静态变量
    static int sum = 10086;   //static只初始化一次
    //2. sum = 10086;
    return sum;
}

int main(int argc, char const *argv[])
{
    // cout << add() << endl;

    //将变量sum起别名
    int &a = add();
    a = 10010;
    cout << add() <<endl;  //使用第一种方式: 10010  //static只初始化一次
                           //使用第二种方式: 10086 输出add()就又重新调用函数
    return 0;
}

总结: 

引用作为函数返回值时,一般可以返回:

静态变量,全局变量,堆空间....  不会被释放的空间就可以!!

6.引用作为函数返回值时 函数可以作为左值

  1. 左值和右值

int a = 10;

等号左侧 左值  --  左值一般是变量

等号右侧 右值 -- 右值一般是常量 也可以是变量

C++
//引用返回
int &res2(){
    static int sum = 100;
    return sum;
}

main(){
    cout << res2() << endl;
   //函数 当做右值处理 -- 没有问题
    int a = res2();
    // int &a = res2();
    // cout << a << endl;
    //函数 当做左值处理 -- 没有问题
    res2() = 300;
    // cout << a << endl;  
    // a = 400;
    cout << res2() << endl;
}

总结: 引用作为函数返回值时 函数可以作为左值

7.引用的注意事项

  1. 引用必须要初始化(引用就是起别名,没有对象就没有起名的意义)
  1. 引用常量,需要使用const常量引用方式   或  && 右值引用
  1. 引用的类型必须匹配
  1. 当引用初始化之后,不能再次修改(和指针不同,因为指针可以修改)

一个别名(引用)只能表示一个人(初始化之后不能被再次修改)

 一个人可以有多个别名(一个引用对象可以被多次引用)

C++
 //1 定义空引用是错误的!!!必须初始化!!
    // int &a;

    /*
    //2 引用常量
    //方式1
    // int &a = 100;  //错误
    const int &a = 100;
    //方式2 &&右值引用
    int &&b = 200;
    cout << b << endl;
    */

    /*
    //3 引用类型必须匹配
    int m = 123;
    int &n = m;
    // char &k = m;  //错误 引用类型不匹配

    //练习 为p和str 取一个引用
    int * p = &m;
    char str[100] = {"hello"};

    int * &x = p;
    char (&y) [100] = str;
    */
    //4 当引用初始化之后 无法再次修改
    int f = 100;
    int g = 200;

    // int *ptr = &f;  // 指针指向f的地址
    //     ptr = &g;  // 指针指向g的地址

    int &yy = f; //初始化
        yy = g;  //想让yy重新引用b --无效                // 相当于单纯给yy赋值 地址没有修改
    cout << &f <<endl;
    cout << &g <<endl;
    cout << &yy << endl;
    //输出的是yy重新赋的值
    cout << yy << endl;
    // f也会发生改变
    cout << f << endl;

    int &xx = f;
    cout << &xx << endl;

二. C++中的多态

多态: 一个对象 作用于不同的事物,得到的结果不同

人  ----> 卧室的床  ----> 睡觉状态

人  ----> 教室的桌上 -->学习状态

人 ----->网吧的电脑 ----> 玩游戏的状态

提高代码的复用性!!!

优点:  设计一个接口, 实现不同的功能

静态多态:程序在编译时,已经确定要执行的状态

动态多态:程序在运行时,才能确定要执行的状态

C++中 函数重载 就相当于 静态多态  

函数重载---一个函数可以实现不同的功能

三. 函数重载

1.函数重载的定义

1 相同函数名 定义不同功能 称为函数重载

2 重载的函数:根据参数的个数,参数类型进行区分

C++
int pf(){
    cout << "打印一个整型数据:" << a << endl;
    return 0;
}

//函数重载
int pf(double b){
    cout << "打印一个浮点型数据:" << b << endl;
    return 0;
}

int pf(char c){
    cout << "打印一个字符:" << c << endl;
    return 0;
}

int main(int argc, char const *argv[])
{
    //调用函数
    pf(123);
    pf(12.3);
    pf('M');
    return 0;
}

2.函数重载的原理

  1. C++编译器在编译时会自动检查用户在编写函数时的参数列表,根据参数列表中参数的不同(个数,类型)对函数名别名化,从而产生多个名称不同的函数,
  1. 函数调用时,根据用户传入的参数自动推导执行哪个函数

练习: 实现两个数据相加(不要失去精度)

C++
extern "C"{
    #include <stdio.h>
}

//整型相加
int add(int a, int b){
    return a+b;
}

//浮点型相加
double add(double a, double b){
    return a+b;
}

//字符串相加--连接
char * add(const char * str1,const char * str2){
    static char str[100] = {0};
    sprintf(str,"%s %s",str1,str2);    return str;
}

//计算两个数据相加 (不失精度)
int main(int argc, char const *argv[])
{
    cout << add(10,20) <<endl;
    cout << add(10.12,20.34) <<endl;
    cout << add("hello","world") <<endl;
    return 0;
}

函数重载的注意事项:

1.函数重载时函数名必须相同

2.函数重载的依据是 : 参数个数和参数的类型 不一样

3 返回值类型不能作为重载的依据

4 调用重载函数时 防止歧义产生(有可能形参有默认值)

3.函数的默认参数

默认参数: 在c++中定义函数时,可以使用默认参数进行形参赋值

C++
//int a = 100就是默认参数
int pf(int a=100){
    return a;
}
作用: 简化函数的调用
例如:mmap
void my_mmap(int fd,size_t length ,void *addr=NULL, int prot = PROT_READ|PROT_WRITE, int flags=MAP_SHARED,off_t offset = 0){

    return  mmap(fd,length ,addr, prot, flags,offset);
}

注意:

定义函数时, 默认参数赋值从右往左(有参数值的往右放,没参数值的往左放)

调用函数时,实参传递给形参是从左往右

十. 面向对象与面向过程

面向过程--洗衣服:

1.我找到脏衣服,

2.打开洗衣机,

3.将衣服放进洗衣机中

4.倒入洗衣液

5.洗衣机转动洗衣服

6.洗衣机甩干衣服

7.我将衣服拿出来晾晒

面向对象 -- 解决办法

抽离两个对象: 我这个人  洗衣机

对象:人

1 人.找脏衣服

2 人.打开洗衣机

3 人.倒入洗衣液

4.人.拿衣服晾晒

对象:洗衣机

1 洗衣机.洗衣服

2.洗衣机.甩干衣服

面向过程: find.c    wash.c

面向对象: class find,   class show

总结一句话: 面向对象就是将面向过程中功能代码想办法都写入到类中

四.  c++中的类(核心)

1.类的三大特征:  封装 继承 多态

  1. 封装:
  • 将功能接口(函数)封装到类中使用
  • 把数据成员封装到类中使用
  1. 继承 :
  • 子类 继承 父类的接口或者数据

        优点: 

          子类直接继承父类的接口函数, 就不需要重新开发接口

      提高了代码的复用性 有利于软件版本的升级

  1. 多态
  • 一个对象作用于不同的事物,所得到的结果(功能)不同

优点: 提高了代码的复用性

2.类的定义

语法:

C++
class 类名{

    成员列表;

    方法....
}

以上类的定义是最简单的定义方式,没有什么意义,默认成员和方法都是私有的,外界无法访问

需要修饰符来修饰成员和方法:

public  公有的                -------  外界可以访问

protected  受保护的     -------  外界不可以访问

private  私有的              -------  外界不可以访问

五. C++中的构造函数

构造函数:

1 函数名和类名相同

2 函数没有返回值

3 函数不需要用户调用,创建对象的时候自动调用

构造函数作用: 用于定义对象时,初始化对象的数据成员

语法:

C++
class  类名{

    public:

    类名(){
        //构造函数
    }

}

案例:

C++
//定义类
class base{
    public:
    // 构造函数必须写在public公共区
    // 否则 无法创建对象
    //构造函数----函数名和类名同名
    //无参构造函数
    base(){
        cout << "创建对象,自动调用构造函数" << endl;
    }

    //带参构造函数
    base(int a){
        num = a;
        cout << num << endl;
    }

    private:
    int num;
};

int main(int argc, char const *argv[])
{
    //定义对象调用构造函数  -- 无参
    base a;
    //定义对象时传入参数   --  带参
    base b(10086);
    return 0;
}

注意:

  • 构造函数必须写在公共区public里, 因为定义对象时会自动调用, 只有在公共区才可以被外界直接访问调用
  • 假设用户没写任何的构造函数,系统会自动生成无参构造函数

练习: 设计一个学生类,公有成员姓名name(char *),保护成员money(double),私有成员密码pwd(int)

C++
定义一个构造函数初始化这些数据成员 并写一个输出接口
#include <iostream>
using namespace std;
extern "C"{
    #include <string.h>

}
/*
设计一个学生类,
公有成员姓名name(char *),
保护成员money(double),
私有成员密码pwd(int)
定义一个构造函数初始化这些数据成员
并写一个输出接口
*/
class Stu{
    public:
    char name[40];

    //解决方式1: 函数重载
    // Stu(){
    //     cout << "构造函数被调用" << endl;
    // }

    //正常步骤
    // Stu(const char * n,double m, int p){
    //     cout << "构造函数被调用" << endl;
    //     //初始化
    //     strncpy(name,n,strlen(n)+1);
    //     money = m;
    //     pwd = p;
    // }

    //解决方式2: 默认参数
    //构造函数
    Stu(const char * n="ZQ",double m=1.34, int p=123456){
        cout << "构造函数被调用" << endl;
        //初始化
        strncpy(name,n,strlen(n)+1);
        money = m;
        pwd = p;
    }
    void show(){
        cout << "name:" << name << endl;
        cout << "money:" << money << endl;
        cout << "pwd:" << pwd << endl;
    }

    protected:
    double money;


    private:
    int pwd;
};

int main(int argc, char const *argv[])
{
    //定义对象  -- 必须传参
    Stu obj("ZQ",12345567.8,123456);
    //调用接口
    obj.show();

    //想法: 创建对象时 不传递参数 -- 简化
    // 解决方式1: 函数重载
    // Stu pp;

    //解决方式2: 默认参数
    Stu pp;

    return 0;
}

总结:

构造函数支持函数重载

  • 构造函数可以设置默认参数


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值