{C++系列} C++基础 day03 C++的引用,引用和指针,类型转换,类和对象,类的定义和实例化
in C/C++ with 0 comment

{C++系列} C++基础 day03 C++的引用,引用和指针,类型转换,类和对象,类的定义和实例化

in C/C++ with 0 comment

#复习:

1)函数重载

2)哑元参数

3)缺省参数

4)内联函数 inline

4 动态内存分配

new/delete
new[]/delete[]

5 C++引用

================================

C++的引用(Reference)

1)将引用用于函数的参数,这时形参就等于是实参的别名,通过引用型的参数就可以直接修改实参的值。
2)将引用用于函数的参数,可以减小函数调用的开销。
3)引用型参数有可能意外修改实参的值,如果不希望通过引用参数修改实参变量,可以将其定义为常引用,在提高传参效率的同时还可以接收常量型的实参。

4 引用型函数返回值

eg:
  int& func(void){
          static int a = 100;
          return a;
  }
func()//结果就是a的引用(别名),不再是临时变量
func() = 200;//ok

注:不要从函数中返回局部变量的引用,因为所引用的内存会在函数返回以后被释放,使用非常危险!但是可以返回成员变量、静态变量、全部变量的引用。

#举例

引用型函数返回值

#include <iostream>
using namespace std;

struct A{
    int data;
    //foo返回结果就是data的别名,是左值,可以直
    //接修改,但是这样代码可读性差,为了避免在
    //函数外部直接去修改,可以附加const
    /*const*/ int& foo(void){
        return data;
    }
    //返回局部变量引用:危险!
    int& bar(void){
        int data = 123;
        return data;
    }
};
int main(void)
{
    A a = {100};
    cout << "a.data=" << a.data << endl;//100
    //a.data = 200
    a.foo() = 200;
    cout << "a.data=" << a.data << endl;//200
    return 0;
}

4 引用和指针

1)从C语言角度分析引用的本质,就是指针

但是C++中尽量多使用引用而不是指针

int i = 100;
int* const pi = &i;
int& ri = i;
ri <==> *pi

//笔试题:引用和指针的区别

2)指针可以不做初始化,其指向目标可以修改(除了指针常量);而引用必须在定义同时初始化,而其所引用的目标不能再修改;

eg:
int a = 3,b = 5;
int* p;//可以不做初始化
p = &a;//p指向a
p = &b;//p指向b

int& r;//error
int& r = a;//r是a的引用
r = b;//赋值操作,不是修改引用的目标

//后面和高级指针相关了解

3)可以定义指针的指针(二级指针),但是不能定义引用的引用。

eg:
  int a = 123;
  int* p = a;
  int** pp = &p;//pp称为二级指针,ok
  ------------------
  int& r = a;
  //int&&在C++98中error,在C++11中称为右值引用
  int&& rr = r;//不能定义引用的引用,error
  int& r2 = r;//ok,r2是a的另一个别名,不能称为引用的引用

4)可以定义指针变量的引用,不能引用变量的指针

eg:
      int a = 100;
      int* p = &a;
      int*& rp = p;//rp指针变量的引用,ok
      ----------
      int& r = a;
      int&* pr = &r;//引用变量的指针,error

5)可以定义指针数组,但是不能定义引用数组

eg:
    int a = 10,b = 20,c = 30;
    int* parr[3] = {&a,&b,&c};//指针数组,ok
    int& rarr[3] = {a,b,c};//引用数组,error

6)可以数组引用(给数组的别名)

eg:
   int arr[3] = {10,20,30};
   int (&rarr)[3] = arr;//rarr是arr别名,ok

7)和函数指针类似也可以定义函数的引用

eg:
void func(int a,int b){...}
int main(void){
   //rfunc是func别名
    void (&rfunc)(int,int) = func;
    rfunc(10,20);
}

十一 类型转换

1 隐式类型转换

eg:
  char c = 'A';
  int i = c;//隐式转换
  ------------
  void foo(int i){...}
  foo(c);//隐式转换
  ------------
  int func(void){
          char c = 'A';
          return c;//隐式转换
  }

2 C++兼容C中强制转换

char c = 'A';
int i = (int)c;//C风格强制转换
int i = int(c);//C++风格强制转化

3 C++增加了四种操作符形式的显式类型转换
1 静态类型转换

语法:
目标类型变量 = static_cast<目标类型>(源类型变量);
适用场景:
主要用于将void*转换为其它类型的指针;

eg:
    char c = 'A';
      int i = static_cast<int>(c);    
    ------------------
    int a = 123;
    void* pv = &a;
    int* pi = static_cast<int*>(pv);

#举例

static_cast类型转换举例

#include <iostream>
using namespace std;

int main(void)
{
    int* pi = NULL;
    //char c = (int)pi;//C风格
    char c = int(pi);//C++风格
    
    void* pv = pi;
    //合理静态类型转换:ok
    pi = static_cast<int*>(pv);

    //不合理静态类型转换:error
    //c = static_cast<int>(pi);
    return 0;
}

2)动态类型转换(后面讲)
语法:
目标类型变量 = dynamic_cast<目标类型>(源类型变量);

3)常类型转换
语法:
目标类型变量 = const_cast<目标类型>(源类型变量);
适用场景:
去除一个指针或引用的常属性。

eg:
   const int a = 123;
    const int* p = &a;
    *p = 321;//error
    int* p2 = const_cast<int*>(&a);
    *p2 = 321;//ok
    ----------------------
    const int& r = a;
    r = 100;//error
    int& r2 = const_cast<int&>(a);
    r2 = 100;//ok

#举例

常类型转换举例

#include <iostream>
using namespace std;

int main(void)
{
    /*volatile修饰变量表示是易变的,告诉编译器
     * 每次在使用该变量时都要小心从内存从重新
     * 加载一次,而不使用寄存器中的副本,防止
     * 编译器优化所带来的错误结果*/
    volatile const int ci = 100;
    int* pci = const_cast<int*>(&ci);
    *pci = 200;//ok
    cout << "ci=" << ci << endl;
    cout << "*pci=" << *pci << endl;
    cout << "&ci=" << (void*)&ci << endl;
    cout << "pci=" << (void*)pci << endl;
    return 0;
}

4)重解释类型转换
语法:
目标类型变量 = reinterpret_cast<目标类型>(源类型变量);
适用场景:
--》任意类型指针或引用之间进行转换
--》在指针和整数之间进行转换

#举例

重解释类型转换举例

#include <iostream>
using namespace std;

int main(void)
{
    int addr = 0x12345678;
    int* paddr = reinterpret_cast<int*>(addr);
    //*paddr = ...
    cout << (void*)paddr << endl;

    //"\000"->'\0'-->0
    char buf[] = "0001\00012345678\000123456";
    struct Data{
        char type[5];
        char id[9];
        char passwd[7];
    };
    Data* pdata = reinterpret_cast<Data*>(buf);
    cout << pdata->type << endl;
    cout << pdata->id << endl;
    cout << pdata->passwd << endl;
    return 0;
}

小结:

1 慎用宏,使用constenuminline替换

eg:
#define PAI 3.14
    --> const double PAI = 3.14;

#define STATE_SLEEP 0
#define STATE_RUN   1
#define STATE_STOP  2
    --> enum STATE{SLEEP,RUN,STOP};

#define max(a,b) ((a)>(b)?(a):(b))
    --> inline int max(int a,int b){
            return a>b?a:b;    
         }

2 变量随用随声明同时初始化

3 尽量使用new/delete取代C中malloc和free

4 少用void*和指针计算,尽可能使用引用替换

5 少用联合体和强制转换

6 尽量使用string表示字符串,少用C风格char*

====================================

十二 类和对象

1 什么是对象

万物皆对象,任何一种事物都可以看做是对象。

2 如何描述和表达对象

通过对象的属性(名词、数量词、形容词)和行为(动词)来描述和表达对象。

eg:描述冰箱对象
  属性:品牌、容量、颜色、功耗
  行为:装东西、冷冻、冷藏

3 面向对象程序设计

对自然世界中对象的观察引入到编程实践中的一种方法,这种方法称为"数据抽象",即在描述对象时把对象的细节剥离出去,只考虑一般性的,有规律性的和统一性的东西。

4 什么是类

类是将多个对象的共性提出来定义的一种新的数据类型,是对 对象属性和行为的抽象描述。

eg:定义表示学生类
属性:姓名、年龄、学号
行为:吃饭、睡觉、学习

十三 类的定义和实例化

1 类的语法形式

class/struct 类名:继承方式 基类,...{
访问控制限定符:
    类名(形参表):初始化表{函数体}//构造函数
    ~类名(void){函数体}//析构函数
    返回类型 函数名(形参表){函数体}//成员函数
    数据类型 变量名;//成员变量
};  

2 访问控制限定符

eg:
struct/class A{
public:
  aaa;//公有成员
private:
  bbb;//私有成员
public:
  ccc;//公有成员
};

#举例

#include <iostream>
using namespace std;

//实现一个描述学生的类
//struct Student{
class Student{
public:
    //行为:成员函数
    void who(void){
        cout << "我叫" << m_name << ",今年" <<
            m_age << "岁,学号是" << m_no << endl;
    }
    void eat(const string& food){
        cout << "我吃" << food << endl;
    }
    void sleep(int hour){
        cout << "我睡了" << hour << 
            "小时" << endl;
    }
    void learn(const string& course){
        cout << "我在学" << course << 
            "课程" << endl;
    }
    //在定义类时,可以把一些不希望在类的外部随意访问
    //的成员封装为私有成员,然后提供公有的接口函数
    //来间接访问,可以在该函数中对非法数据加以限定
    //控制业务逻辑的合理性。
    void setName(const string& name){
        if(name == "二")
            cout << "你才" << name << endl;
        else
            m_name = name;
    }
    void setAge(int age){
        if(age < 0)
            cout << "无效年龄" << endl;
        else
            m_age = age;
    }
    void setNo(int no){
        if(no < 1000)
            cout << "无效学号" << endl;
        else
            m_no = no;
    }
private:
    //属性:成员变量
    string m_name;//姓名
    int m_age;//年龄
    int m_no;//学号
};
int main(void)
{
    //以前叫定义结构体类型变量,
    //现在称为:创建对象 或者 实例化对象
    Student s;
    /*s.m_name = "张飞";
    s.m_name = "二";
    s.m_age = 28;
    s.m_no = 10086;*/
    s.setName("二");
    s.setName("张翼德");
    s.setAge(-2);
    s.setAge(29);
    s.setNo(250);
    s.setNo(10011);

    s.who();
    s.eat("牛肉拉面");
    s.sleep(8);
    s.learn("C++");
    return 0;
}

练习:参考Student类,自己实现一个美女类..

Responses