day3学习笔记

十一 类型转换
1 隐式类型转换

  char c = 'A';
  int i = c;//隐式
  -----------------
  void func(int i){}
  func(c);//隐式
  -----------------
  int func(void){
  		char c='A';
  		return c;//隐式
  }

2 显示类型转换
2.1 C++兼容C中强制类型转换
char c = ‘A’;
int i = (int)c;//C风格
int i = int©;//C++风格

2.2 C++扩展了四种操作符形式显式转换
1)静态类型转换:static_cast
语法:
目标变量 = static_cast<目标类型>(源类型变量);
适用场景:
主要用于将void*转化为其它类型的指针,转换时做静态检查,编译时进行

double d=3.14
int i=static_cast<int>(d)
int *p=static_cast<int*>(malloc(sizeof(int)*10))

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

3)去常类型转换:const_cast
语法:
目标变量 = const_cast<目标类型>(源类型变量);
适用场景:
主要用于去掉指针或引用const属性.

const volatile int CI=12345;
int *pci=const_cast<int *>(&CI)

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

eg:已知物理内存地址0x12345678,向该地址存放一个整型数100?
int* paddr = reinterpret_cast<int*>(0x12345678);
*paddr = 100;

小结:
1 慎用宏,可以使用const、enum、inline替换
#define PAI 3.14
–》const double PAI = 3.14;

#define SLEEP 0
#define RUN 1
#define 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替换malloc/free
4 少用void*,指针计算,联合体和强制转换
5 尽量使用string表示字符串,少用C风格的char*/char[],string和vector可以简化程序


十二 类和对象//了解
1 什么是对象
万物皆对象,任何一种事物都可以看做是对象.

2 如何描述对象
通过对象的属性和行为来描述对象.

3 面向对象程序设计
对自然世界中对象观察和描述引入到编程中一种理念和方法,这种方法称为"数据抽象",即在描述对象时把细节东西玻璃出去,只考虑一般性的、有规律性的、统一性的东西.

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

现实世界 类 虚拟世界
具体对象–抽象–>属性/行为–实例化–>具体对象

十三 类的定义和实例化
1 类定义的一般语法形式
struct/class 类名:继承方式 基类,…{
访问控制限定符:
类名(形参表):初始化列表{}//构造函数
~类名(void){}//析构函数
返回类型 函数名(形参表){}//成员函数
数据类型 变量名;//成员变量
};
2 访问控制限定符
1)public:公有成员,任何位置都可以访问。
2)private:私有成员,只有类自己的成员函数才能访问,以及类的友元访问
3)protected:保护成员(后面讲)
注:如果struct定义类默认的访问控制属性是public;而如果是class定义类默认的访问控制属性是private.
eg:
struct/class XX{
int m_a;//默认访问属性
public:
int m_b;//公有成员
private:
int m_c;//私有成员
public:
int m_d;//公有成员
};

#include <iostream>  
using namespace std;  
//原来:定义结构体  
//现在:定义类  
//struct Student{  
class Student{  
public:  
    //行为:成员函数  
    void eat(const string& food){  
        cout << "我在吃" << food << endl;  
    }  
    void sleep(int hour){  
        cout << "我睡了" << hour << "小时"   
            << endl;  
    }  
    void learn(const string& course) {  
        cout << "我在学" << course << endl;  
    }  
    void who(void){  
        cout << "我叫" << m_name << ",今年" <<  
.            m_age << "岁,学号是" <<m_no<<endl;  
    }  
public:  
    /* 类中的私有成员不能在外部直接访问,但是可 
     * 以提供类似如下的公有成员函数来间接访问, 
     * 在函数中可以对非法数据加以限定控制业务 
     * 逻辑的合理性,这种编程思想就是"封装".*/  
    void setName(const string& newName){  
        if(newName == "二")  
            cout << "你才二" << endl;  
        else  
            m_name = newName;  
    }  
    void setAge(int newAge){  
        if(newAge < 0)  
            cout << "无效年龄" << endl;  
       else  
            m_age = newAge;  
    }  
    void setNo(int newNo){  
        if(newNo < 0)  
            cout << "无效学号" << endl;  
        else  
            m_no = newNo;  
    }  
private:  
    //属性:成员变量  
    string m_name;  
    int m_age;  
    int m_no;  
};  
int main(void){  
    //原理:定义结构体变量  
   //现在:创建对象/实例化对象/构造对象  
    Student s;  
    /*s.m_name = "张飞"; 
    s.m_name = "二"; 
    s.m_age = 25; 
    s.m_no = 10011;*/  
    s.setName("张翼德");  
    s.setName("二");  
   s.setAge(26);  
   s.setAge(-2);  
    s.setNo(10086);  
    s.setNo(-1);  
    s.who();  
    s.eat("牛肉拉面");  
    s.sleep(8);  
    s.learn("C++编程");  
  
    return 0;  
}  

3 构造函数(constructor)
1)语法
class 类名{
类名(参数表){
主要负责初始化对象,即初始化成员变量。
}
};
2)函数名和类名一致,没有返回类型。
3)构造函数在创建对象时自动被调用,不能像普通的成员函数一样显式的调用.
4)在每个对象的生命周期,构造函数一定会被调用,且仅会被调用一次。

练习:实现一个电子时钟类,使用构造函数初始化时钟的时间为当前的系统时间,并可以以秒为单位运行

1. #include <iostream>  
2.#include <cstdio>                 
3.#include <ctime>  
4.#include <unistd.h>  
5.using namespace std;  
6.class Clock{  
7.public:  
8.    Clock(time_t t){  
9.        tm* local = localtime(&t);  
10.        m_hour = local->tm_hour;  
11.        m_min = local->tm_min;  
12.        m_sec = local->tm_sec;  
13.    }  
14.    void run(void){  
15.        while(1){  
16.            printf("\r%02d:%02d:%02d",  
17.                m_hour,m_min,m_sec);  
18.            fflush(stdout);//刷新标准输出流  
19.            if(60 == ++m_sec){  
20.                m_sec = 0;  
21.                if(60 == ++m_min){  
22.                    m_min = 0;  
23.                    if(24 == ++m_hour){  
24.                        m_hour = 0;  
25.                    }  
26.                }  
27.            }  
28.            sleep(1);  
29.        }  
30.    }  
31.private:  
32.    int m_hour;  
33.    int m_min;  
34.    int m_sec;  
35.};  
36.int main(void){  
37.    Clock c(time(NULL));  
38.    c.run();  
39.    return 0;  
40.}  

提示:
class Clock{
public:
构造函数(time_t t){
tm* local = localtime(&t);
时 = local->tm_hour;
分 = local->tm_min;
秒 = local->tm_sec;
}
void run(void){
while(1){打印当前时间;计时+1秒;sleep(1);}
}
private:
int 时,分,秒;
};
Clock c( time(NULL) );
c.run();
很像字符串的使用方法

#include <iostream>  
using namespace std;  
//原来:定义结构体  
//现在:定义类  
//struct Student{  
class Student{  
public:  
    //构造函数  
   Student(const string&name,int age,int no){  
        cout << "构造函数" << endl;  
       m_name = name;  
        m_age = age;  
.        m_no = no;  
    }  
    //行为:成员函数  
    void eat(const string& food){  
       cout << "我在吃" << food << endl;  
    }  
    void sleep(int hour){  
       cout << "我睡了" << hour << "小时"   
            << endl;  
    }  
    void learn(const string& course) {  
       cout << "我在学" << course << endl;  
    }  
    void who(void){  
        cout << "我叫" << m_name << ",今年" <<  
           m_age << "岁,学号是" <<m_no<<endl;  
    }  
public:  
    /* 类中的私有成员不能在外部直接访问,但是可 
     * 以提供类似如下的公有成员函数来间接访问, 
     * 在函数中可以对非法数据加以限定控制业务 
     * 逻辑的合理性,这种编程思想就是"封装".*/  
    void setName(const string& newName){  
        if(newName == "二")  
            cout << "你才二" << endl;  
        else  
            m_name = newName;  
    }  
    void setAge(int newAge){  
        if(newAge < 0)  
            cout << "无效年龄" << endl;  
        else  
            m_age = newAge;  
46.    }  
47.    void setNo(int newNo){  
48.        if(newNo < 0)  
49.            cout << "无效学号" << endl;  
50.        else  
51.            m_no = newNo;  
52.    }  
53.private:  
54.    //属性:成员变量  
55.    string m_name;  
56.    int m_age;  
57.    int m_no;  
58.};  
59.int main(void){  
60.    //创建对象(自动调用构造函数)  
61.    //(...):指定构造函数需要的实参  
62.    Student s("张飞",25,10011);  
63.    s.who();  
64.      
65.    //构造函数不能显式调用  
66.    //s.Student("张三",26,10086);  
67.  
68.    return 0;  
69.}  

4 对象的创建和销毁
1)在栈区创建单个对象 //重点掌握
类名 对象(构造实参表);//直接初始化
类名 对象=类名(构造实参表);//拷贝初始化(实际等价)
eg:
string s;
string s(“hello”);
string s = string(“hello”);//string s = “hello”;

2)在栈区创建多个对象(对象数组)
类名 对象数组[元素个数] = {
类名(构造实参表),类名(构造实参表),…};

3)在堆区创建/销毁单个对象 //重点掌握
创建:
类名* 对象指针 = new 类名(构造实参表);
注:new操作符会先分配内存再自动调用构造函数,完成对象的创建和初始化;而如果是malloc函数只能分配内存,不会调用构造函数,不具备创建对象能力.

销毁:
delete 对象指针;

4)在堆区创建/销毁多个对象
创建:
类名* 对象指针 = new 类名[元素个数] {
类名(构造实参表),类名(构造实参表),…};
销毁:
delete[] 对象指针;

1.#include <iostream>  
2.using namespace std;  
3.//原来:定义结构体  
4.//现在:定义类  
5.//struct Student{  
6.class Student{  
7.public:  
8.    //构造函数  
9.    Student(const string&name,int age,int no){  
10.        cout << "构造函数" << endl;  
11.        m_name = name;  
12.        m_age = age;  
13.        m_no = no;  
14.    }  
15.    //行为:成员函数  
16.    void eat(const string& food){  
17.        cout << "我在吃" << food << endl;  
18.    }  
19.    void sleep(int hour){  
20.        cout << "我睡了" << hour << "小时"   
21.            << endl;  
22.    }  
23.    void learn(const string& course) {  
24.        cout << "我在学" << course << endl;  
25.    }  
26.    void who(void){  
27.        cout << "我叫" << m_name << ",今年" <<  
28.            m_age << "岁,学号是" <<m_no<<endl;  
29.    }  
30.public:  
31.    /* 类中的私有成员不能在外部直接访问,但是可 
32.     * 以提供类似如下的公有成员函数来间接访问, 
33.     * 在函数中可以对非法数据加以限定控制业务 
34.     * 逻辑的合理性,这种编程思想就是"封装".*/  
35.    void setName(const string& newName){  
36.        if(newName == "二")  
37.            cout << "你才二" << endl;  
38.        else  
39.            m_name = newName;  
40.    }  
41.    void setAge(int newAge){  
42.        if(newAge < 0)  
43.            cout << "无效年龄" << endl;  
44.        else  
45.            m_age = newAge;  
46.    }  
47.    void setNo(int newNo){  
48.        if(newNo < 0)  
49.            cout << "无效学号" << endl;  
50.        else  
51.            m_no = newNo;  
52.    }  
53.private:  
54.    //属性:成员变量  
55.    string m_name;  
56.    int m_age;  
57.    int m_no;  
58.};  
59.int main(void){  
60.    //在栈区创建单个对象  
61.    //Student s("张飞",25,10011);  
62.    Student s = Student("张飞",25,10011);  
63.    s.who();  
64.      
65.    //在栈区创建多个对象  
66.    Student sarr[3] = {  
67.        Student("赵云",22,10012),  
68.        Student("马超",26,10013),  
69.        Student("刘备",27,10014)};  
70.    sarr[0].who();  
71.    sarr[1].who();  
72.    sarr[2].who();  
73.      
74.    //在堆区创建单个对象  
75.    Student* ps=new Student("貂蝉",20,10015);  
76.    ps->who();//(*ps).who();  
77.    delete ps;  
78.    ps=NULL;  
79.  
80.    //在堆区创建多个对象,C++11支持  
81.    Student* parr = new Student[3] {  
82.        Student("小乔",22,10016),  
83.        Student("大乔",25,10017),  
84.        Student("孙尚香",26,10018) };  
85.    parr[0].who();//(parr+0)->who()  
86.    parr[1].who();//(parr+1)->who()  
87.    parr[2].who();//(parr+2)->who()  
88.  
89.    delete[] parr;  
90.    parr = NULL;  
91.  
92.  
93.    return 0;  
94.}  

5 多文件编程:类的声明和定义可以分别放在不同的文件中
1)类的声明一般放在头文件中(xx.h)
2)类的实现一般放在源文件中(xx.cpp)
//类似qt中的那种写法

十四 构造函数和初始化列表
1 构造函数可以重载,也可以带有缺省参数
//匹配string的无参构造函数
string s;
//匹配string的有参(const char*)构造函数
string s(“hello”);
---------------------------------
http://www.cplusplus.com/

2 缺省构造函数(无参构造函数)
1)如果类中没有定义任何构造函数,编译器会为该类提供一个缺省(无参)构造函数:
–》对于基本类型成员变量不做初始化
–》对于类 类型的成员变量(成员子对象),将会自动调用相应类的无参构造函数来初始化

2)如果自己定义了构造函数,无论是否有参数,那么编译器都不会再提供缺省的无参构造函数了.

3 类型转换构造函数(单参构造函数) //构造函数的类型转换
class 类名{
//可以将源类型变量转换为当前类类型对象.
类名(源类型){…}
};
-----------------------------------
class 类名{
//加“explicit”关键字修饰,可以强制要求这种类型
//转换必须显式的完成.
explicit 类名(源类型){…}
};

4 拷贝构造函数(复制构造函数)
1)用一个已存在的对象作为同类对象的构造实参,创建新的副本对象时,会调用该类拷贝构造函数。
class 类名{
类名(const 类名&){//拷贝构造

}
};
------------
eg:
class A{…};
A a1(…);
A a2(a1);//匹配A的拷贝构造函数

2)如果一个类没有自己定义拷贝构造函数,那么编译器会为该类提供一个缺省的拷贝构造函数:
–》对于基本类型的成员变量,按字节复制
–》对于类类型的成员变量(成员子对象),将自动调用相应类的拷贝构造函数来初始化

注:一般不需要自己定义拷贝构造函数函数,因为编译器缺省提供的已经很好用了.

class A1{};//缺省无参,缺省拷贝
class A2{//缺省拷贝
	A(void){}
};
class A3{//缺省拷贝
	A(int){}
};
class A4{//没有缺省构造
	A(const A&){}
};

3)拷贝构造函数调用时机
–》用一个已存在对象作为同类对象的构造实参
–》以对象形式向函数传递参数
–》从函数中返回对象(有可能被编译器优化掉)

1.#include <iostream>  
2.using namespace std;  
3.class Integer{  
4.public:  
5.    Integer(void){  
6.        m_i = 0;  
7.    }  
8.    //int->Integer  
9.    /*explicit*/ Integer(int i){  
10.    cout << "类型转换构造函数" << endl;  
11.    m_i = i;  
12.    }  
13.    void print(void){  
14.        cout << m_i << endl;  
15.    }  
16.private:  
17.    int m_i;  
18.};  
19.  
20.  
21.int main(void){  
22.    Integer i;    
23.    i.print();//0  
24.    //1)通过类型转换构造函数将100转为Integer对  
25.    //象,转换结果会保存到一个临时对象中  
26.    //2)再使用临时对象对i进行赋值操作  
27.  
28.    //在不添加explicit的时候,可以完成隐式转化,添加之后,隐式转换会报错  
29.    i = 100;  
30.    i.print();//100  
31.      
32.    //上面代码可读性差,推荐使用下面显式转换  
33.    //i = (Integer)200;//C风格  
34.    i = Integer(200);//C++风格  
35.    i.print();//200  
36.  
37.    return 0;  
38.}  


1.#include <iostream>  
2.using namespace std;  
3.class A{  
4.public:  
5.    A(int data = 0){  
6.        cout << "A(int=0)" << endl;  
7.        m_data = data;  
8.    }  
9.    //拷贝构造函数  
10.    A(const A& that){  
11.        cout << "A(const A&)" << endl;  
12.        //a2.m_data = a1.m_data  
13.        m_data = that.m_data;     
14.    }  
15.    int m_data;  
16.};  
17.int main(void){  
18.    const A a1(123);  
19.    //A a2(a1);  
20.    A a2 = a1;//和上面等价  
21.    cout << a1.m_data << endl;//123  
22.    cout << a2.m_data << endl;//123  
23.    return 0;  
24.} 

1.#include <iostream>  
2.using namespace std;  
3.class A{  
4.public:  
5.    A(int data = 0){  
6.        cout << "A(int=0)" << endl;  
7.        m_data = data;  
8.    }  
9.    //拷贝构造函数  
10.    A(const A& that){  
11.        cout << "A(const A&)" << endl;  
12.        //a2.m_data = a1.m_data  
13.        m_data = that.m_data;  
14.    }  
15.    int m_data;  
16.};  
17.class B{  
18.public:  
19.    A m_a;//成员子对象  
20.};  
21.int main(void){  
22.    B b1;  
23.    B b2(b1);//拷贝构造  
24.    cout << b1.m_a.m_data << endl;//0  
25.    cout << b2.m_a.m_data << endl;//0  
26.    return 0;  
27.}  


1.#include <iostream>  
2.using namespace std;  
3.class A{  
4.public:  
5.    A(void){  
6.        cout << "A的无参构造" << endl;  
7.    }  
8.    A(const A& that){  
9.        cout << "A的拷贝构造" << endl;  
10.    }  
11.};  
12.void func1(A a){}  
13.A func2(void){  
14.    A a;//无参  
15.    cout << "&a:" << &a << endl;  
16.    return a;//拷贝  
17.}  
18.int main(void){  
19.    A a1;//无参  
20.    A a2 = a1;//拷贝  
21.    func1(a1);//拷贝  
22.    /* 正常情况func2返回a拷贝到临时对象,临时 
23.     * 对象在拷贝给a3,发生两次拷贝;现在因为编 
24.     *  译器优化,让a3直接引用a,不再发生拷贝. 
25.     * 去优化选项: 
26.      g++ 10cpCons.cpp -fno-elide-constructors 
27.     * */  
28.    A a3 = func2();//拷贝  
29.    cout << "&a3:" << &a3 << endl;  
30.    return 0;  
31.}  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值