C++学习笔记_three_day

C++ ----- 一种数据类型

-------class

属性:--------类 内部的数据

行为:--------类 内部的函数

类的变量 ------对象

类(种类) ------对象

描述事物(学生)  具体的事物(吴尚奇)     如:

 

 1 //cat.cc
 2 #include<string.h>
 3 
 4 #include<iostream>
 5 using namespace std;
 6 
 7 //猫类
 8 class Cat
 9 {
10 //属性
11     char m_name[20];  //名子 //m->member成员
12 
13 public://访问修饰符,  - 控制类 内部成员的访问权限
14 
15 //行为
16     //取名子
17     void Setname(const char *name)
18     {
19         strcpy(m_name,name);
20         return;
21     }
22     //吃食物
23     void eat()
24     {
25         cout<<m_name<<" 吃鱼 "<<endl;
26     }
27 };
28 
29 int main(int argc,char **argv)
30 {
31     Cat cat;//创建了一个cat对象
32     cat.Setname("Jinshan");
33     cat.eat();
34 
35     return 0;
36 }

 

2.访问修饰符- 控制类 内部成员的访问权限

作用是:限制类 内部成员(数据和函数)的访问(调用)

public共有的访问修饰符

让成员在任何地方使用

Struct 的默认访问权限是public

Class 的默认访问权限是 private

protected 受保护的访问修饰符

private私有的访问修饰符

Protectedprivate只能在类的内部使用

Class A{ |<--------类的内部------->| };

通过访问修饰符 将 类 内部的重要数据进行隐藏

类的性质:

隐藏:通过访问修饰符 将 类 内部的重要数据进行隐藏

封装:将数据和函数绑定成一个逻辑单元

私有成员的访问:

一般使用共有的函数进行访问

Set()/Get()人为定义的

 

 1 //process.cc
 2 #include<iostream>
 3 using namespace std;
 4 
 5 class Test
 6 {
 7 public:
 8     int m_a1;  //若上面没有public则默认m_a1是private修饰
 9 protected:
10     int m_a2;
11 private:
12     int m_a3;
13 
14 public:
15     void value(int a1, int a2, int a3)
16     {
17         m_a1=a1;
18         m_a2=a2;
19         m_a3=a3;
20     }
21     void show()        //m_a2和m_a3只能在类 的内部访问,在主函数里面是访问不到的
22     {
23          cout<<" m_a2="<<m_a2<<" m_a3="<<m_a3<<endl;
24          return;
25     }
26 };
27 
28 int main()
29 {
30     Test t1;
31     t1.value(2,3,4);
32 
33     cout<<" m_a1="<<t1.m_a1<<endl;
34     cout<<"**********************"<<endl;
35     t1.show();
36 
37     return 0;
38 }

 

私有成员的访问:

一般使用共有的函数进行访问

set()/get() 人为定义的

 1 //Set_get.cc
 2 #include<string.h>
 3 
 4 #include<iostream>
 5 using namespace std;
 6 
 7 class Gir1
 8 {
 9     char m_name[20]; //默认是private的
10 public:
11     //设置 m_name的值
12     void Setname(const char *name )
13     {
14         strcpy(m_name,name);
15         return;
16     }
17 
18     //获得m_name 的 值
19     char  *Getname()
20     {
21         return m_name;
22     }
23 };
24 
25 int main(int argc, char **argv)
26 {
27     //这里的Setname()和Getname()是人为规定的对类内部私有数据访问的合法途径
28     Gir1 g1;
29     g1.Setname("颜栏栏");
30     
31     cout<<"女孩子的名子是 "<<g1.Getname()<<endl;
32 
33     return 0;
34 }

作业:struct和class的区别:

  解答:

class是引用类型,struct是值类型;

class可以继承类、接口和被继承,struct只能继承接口,不能被继承;

class有默认的无参构造函数,有析构函数,struct没有默认的无参构造函数,且只能声明有参的构造函数,没有析构函数;

class可以使用abstractsealed,有protected修饰符,struct不可以用abstractsealed,没有protected修饰符;

class必须使用new初始化,结构可以不用new初始化;

class实例由垃圾回收机制来保证内存的回收处理,而struct变量使用完后立即自动解除内存分配;

从职能观点来看,class表现为行为,而struct常用于存储数据;

作为参数传递时,class变量以按址方式传递,而struct变量是以按值方式传递的。

如何选择使用结构还是类:

1).堆栈的空间有限,对于大量的逻辑的对象,创建类要比创建结构好一些

2).结构表示如点、矩形和颜色这样的轻量对象,例如,如果声明一个含有 1000 个点对象的数组,则将为引用每个对象分配附加的内存。在此情况下,结构的成本较低

3).在表现抽象和多级别的对象层次时,类是最好的选择

4)大多数情况下该类型只是一些数据时,结构是最佳的选择。

  1. 构造函数和析构函数

类里面的成员函数

没有的时候,系统默认提供

构造函数:初始化类的成员数据 constructor

析构函数:释放内存空间

  析构函数在一定意义上可以看作是构造函数的逆操作

 

 1 //coustructor.cc
 2 #include<iostream>
 3 using namespace std;
 4 
 5 class A
 6 {
 7     //构造函数
 8     //1、没有返回值
 9     //2、函数名就是类名
10     //3、在创建一个对象的时候,会自动调用
11     int m_i;
12     double m_d;
13 public:
14     //允许重载函数/可以带参数
15     //功能:
16     //  (1)给成员数据分配内存空间
17     //  (2)初始化成员数据
18     A()
19     {
20         cout<<" wushangqi"<<endl;
21     }
22 
23     //可以带参数的
24     A(int i, double d)
25     {
26         m_i=i;
27         m_d=d;
28         cout<<" A() "<<endl;
29     }
30 
31     void show()
32     {
33         cout<<" m_i= "<<m_i<<endl;
34         cout<<" m_d= "<<m_d<<endl;
35     }
36 };  //don't forget me -> ;
37 
38 int main(int argc, char **argv)
39 {
40     //通过参数列表将实参传给构造函数的形参
41     A a(10,3.14);//创建了一个对象a 根据函数的参数自动匹配
42     a.show();
43     return 0;
44 }

 

析构函数:

 1 //disconstructor.cc
 2 #include<iostream>
 3 using namespace std;
 4 
 5 class A
 6 {
 7     //析构函数
 8     //1、没有返回值
 9     //2、函数名和类名相同
10     //3、用 ~ 修饰函数
11     //4、不带参数的
12 public:
13     //在对象消亡的时候,会自动调用
14     ~A()
15     {
16         cout<<" ~A() "<<endl;
17     }
18         
19 };
20 
21 int main(int argc, char **argv)
22 {
23     A a;
24     cout<<"~~~~~~~~~~~~~飘过~~~~~~~~~~~"<<endl;
25 
26     return 0;//在函数结束的时候消亡,这个时候自动调用析构函数
27 }

作业2:

  析构函数和构造函数可以手动调用吗?(重要)

解答:

构造函数是不能手动调用的。

析构函数可以手动调用。逻辑上是错误的。

C++, 构造函数和析构函数可以被显示调用. 显示调用默认构造函数的语法: a.A::A();(不能写成a.A();) , 显示调用非默认构造函数的语法: a.A::A(7);(不能写成a.A(7);); 显示调用析构函数的语法: a.A::~A();(可以写成a.~A();) .

显示调用构造函数和析构函数就像调用一般的函数一样, 并不意味着创建或销毁对象;

如果构造函数中动态分配了空间, 则显示调用构造函数会造成内存泄露. 创建对象时的隐式构造函数调用已经为对象分配了动态内存. 当用创建好的对象显示调用构造函数时, 对象指向的动态内存更新显示调用时所分配的, 对象生命周期结束时析构函数所释放掉的是后一次分配的动态内存, 也就是说创建对象时隐式构造函数调用所分配的那块内存泄漏了.

如果析构函数中释放动态分配的空间, 则会造成多次释放同一内存, 会出现严重错误.

 

 

 

隐含成员

 

当一个类没有写 构造函数 和 析构函数 的时候 系统会自动提供构造函数和析构函数,一旦程序写了构造函数和析构函数,系统就不会再提供默认的 构造函数和 析构函数

 

构造函数 和 手写函数即使不作任何操作,仍然需要手写,为了 提高调用的速度

 

类的隐藏成员

 

构造函数 和 析构函数

this指针,指向对象的地址

 

 1 //this.cc
 2 #include<iostream>
 3 using namespace std;
 4 
 5 class A
 6 {
 7 public:
 8     void Addr()
 9     {
10         //this 当前对象的地址
11         cout<<" this = "<<this<<endl;
12     }
13 };
14 
15 int main(int argc, char **argv)
16 {
17     A a1;
18     A a2;
19 
20     cout<<endl;
21     cout<<" 打印a1的地址:"<<endl;
22     cout<<" &a1 = "<<&a1<<endl; 
23     a1.Addr();
24     
25     cout<<"---------------------------"<<endl;
26     
27     cout<<" 打印a2的地址:"<<endl;
28     cout<<" &a2 = "<<&a2<<endl; 
29     a2.Addr();
30 
31     return 0;
32 }

 

 1 /*练习1:
 2 设计一个分数类:
 3     一个分数包含分子和分母
 4     (1)设置分数的值
 5     (2)可以按格式打印
 6             12,13   12/13
 7     (3)可以约分(注意+/-符号的处理)
 8             12,-16        -3/4
 9 */
10   //Fract.cc
11 #include <iostream>
12 using namespace std;
13 
14 /**
15 * Fraction
16 **/
17 class Fract
18 {
19     int m_n; // 分子
20     int m_d; // 分母
21 public:
22     Fract(int n,int d);
23     ~Fract(){}
24 
25     void print();  // 打印分数
26     void reduc();  // 约分
27 };
28 
29 Fract::Fract(int n,int d)
30 {
31     m_n = n;
32     m_d = d;    
33 }
34 
35 // 打印分数
36 void Fract::print()
37 {
38     cout << m_n << "/" << m_d << endl;
39     return ;
40 }
41 
42 // 约分
43 void Fract::reduc()
44 {
45     // 处理+/-符号问题
46     if( m_d < 0)
47     {
48         m_d = -m_d;
49         m_n = -m_n;
50     }
51 
52     // 找最大公约数
53     int i;
54     for(i = m_d; i > 1 ; --i)
55     {
56         if( (m_n%i == 0) && (m_d%i == 0))
57         {
58             m_n /= i;
59             m_d /= i;
60             break;
61         }
62     }
63     
64     return ;
65 } 
66 
67 
68 int main(int argc,char **argv)
69 {
70     Fract f(-12,16);
71     f.reduc();
72     f.print(); //  -3/4
73     return 0;
74 }
 1 /*练习2:
 2 设计一个日期类
 3     日期包含 年/月/日
 4     (1)可以设置日期    
 5     (2)判断闰年
 6     (3)输出 当前日期 是 该年的第几天
 7             2014/4/26  -> 2014年的第?天
 8 */
 9           //Data.cc
10 #include <iostream>
11 using namespace std;
12 
13 static int arrday[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
14 
15 /**
16 * 日期类
17 */
18 class Date
19 {
20     int m_year;   //
21     int m_month;  //
22     int m_day;    //
23 public:
24     Date(int year,int month,int day);
25     ~Date(){}
26 
27     // 获得年份
28     int GetYear(){ return m_year;}
29 
30     void show();        // 显示日期
31     bool isLeapYear();  // 判断是否为闰年
32     int DayofYear();    // 今年的第几天
33     
34 };
35 
36 Date::Date(int year,int month,int day)
37 {
38     m_year = year;
39     m_month = month;
40     m_day = day;
41 }
42 
43 // 1.显示日期
44 void Date::show()
45 {
46     cout << m_year << "/"
47          << m_month << "/"
48          << m_day << endl;
49     return ;
50 }
51 
52 // 2.判断是否为闰年
53 bool Date::isLeapYear()
54 {
55     return ( (m_year%4 == 0) && (m_year%100 != 0) ) || (m_year%400 == 0);
56 }
57 
58 // 2014/4/26
59 // 计算前3个月的天数 + m_day
60 
61 // 3.今年的第几天
62 int Date::DayofYear()
63 {
64     int sum = 0;
65 
66     //1.计算m_month之前几个月的天数之和
67     int i;
68     for(i=0; i< m_month - 1; ++i)
69     {
70         sum += arrday[i];
71     }
72 
73     //2.加上m_month本月的天数
74     sum += m_day;
75 
76     //3.二月问题处理
77     if( m_month > 2)
78         sum += isLeapYear();
79 
80     return sum;
81 } 
82 
83 int main(int argc,char **argv)
84 {
85     Date d(2000,4,26);
86     d.show();
87 
88     cout << d.GetYear() << " 是闰年吗? "
89          << (d.isLeapYear()?"":"不是")
90          << endl;
91 
92     cout << "是今年的第 " 
93          << d.DayofYear()
94          << ""  << endl;
95     
96     return 0;
97 }


1局部对象的构造和析构的顺序

最先构造的对象,最后析构

数据存放栈区,先进后出

全局对象/局部对象/静态对象

Class A{};

A a1;//全局

Void fn()

{

A a3;

Static A a4;

}


Int main()

{

A a2;

Fn();

A a5;

Return 0;

}

请问这些对象的构造和析构顺序????????????

  1. C++是如何操作堆空间的

    C语言 malloc() free()

    C++语言 new delete 运算符

 1  //memory.cc
 2 
 3 #include<iostream>
 4 
 5 using namespace std;
 6 
 7 int main(int argc, char **argv)
 8 
 9 {
10 
11 //这里的new和delete是运算符,不是函数
12 
13 int *pi= new int ;//申请堆空间
14 
15 *pi = 10;
16 
17 cout<<" *pi="<<*pi<<endl;
18 
19 delete pi;//释放堆空间
20 
21 return 0;
22 
23 }

 

作业:

Malloc/freenew/delete的区别

从面向对象来说,new/deletemalloc/free的区别是:malloc/free只是单纯的进行内存空间的分配和释放,而使用new/delete时,不仅分配了内存空间,若new/delete的是一个类,还会调用类(经测试,基本类型好像不会进行默认初始化)的构造函数或析构函数。


简单来说,两者的区别主要有:

1. mallocfreeC++/C语言的标准库函数,new/deleteC++的运算符,与"+“、”-“、”*“、”/“有一样的地位。

2. new/delete是可以重载的,而重载之后,就成为了函数。

3. malloc在申请内存的时候,必须要提供申请的长度,而且返回的指针是void*型,必须要强转成需要的类型。

4. new/delete在类中被重载的时候,可以自定义申请过程,比如记录所申请内存的总长度,以及跟踪每个对象的指针。

5. new/delete,其实内部也调用了malloc/free


两者的共同点有

1. 都必须配对使用,防止内存泄露。

2. 都可用于申请动态内存和释放内存,都是在堆中分配内存。

3. freedelete可以释放NULL指针。


注意点:

不建议将new/deletemalloc/free混合使用:将newdeletemallocfree混合使用並不是好主意。當你企圖對著一个「因new而得的指標」呼叫free時,或是對著一個「因malloc而得的指標」呼叫delete時,其結果都未有定義。而我們都知道所謂「未有定義」的意思就是:它在開發階段沒問題,它在測試階段沒問題,但是它會在你最重要的客戶面前突然爆發。


  1. 初始化列表

功能:初始化类的成员数据

 1  //init_list.cc
 2 
 3 #include<iostream>
 4 
 5 using namespace std;
 6 
 7 class A
 8 
 9 {
10 
11 int m_data;
12 
13 int m_data2;
14 
15 public:
16 
17 A(int data,int data2):m_data(data),m_data2(data2)//使用初始化列表初始化成员数据
18 
19 {
20 
21 //使用初始化列表的时候,初始化成员变量并赋值
22 
23 //调用构造函数的时候
24 
25  
26 
27 //m_data=data; m_data2=data2;
28 
29 //调用构造函数的时候
30 
31 //第一步:定义成员数据(分配空间)
32 
33 //第二布:执行构造函数体内的语句
34 
35 cout<<m_data<<endl;
36 
37 cout<<m_data2<<endl;
38 
39 }
40 
41 ~A()
42 
43 {
44 
45  
46 
47 }
48 
49 };
50 
51 int main(int argc,char **argv)
52 
53 {
54 
55 A a(10,13);
56 
57 return 0;
58 
59 }

 

  1. 拷贝构造函数(重新整理)

调用:用一个对象初始化另外一个对象的时候

 1  //copy_construct.cc
 2 
 3 #include<iostream>
 4 
 5 using namespace std;
 6 
 7 class A
 8 
 9 {
10 
11 int m_data;
12 
13 public:
14 
15 A(int data):m_data(data)
16 
17 {
18 
19 cout<<"A()"<<endl;
20 
21 }
22 
23 ~A()
24 
25 {
26 
27 cout<<"~A()"<<endl;
28 
29 }
30 
31 void show()
32 
33 {
34 
35 cout<<" m_data = "<<m_data<<endl;
36 
37 return;
38 
39 }
40 
41 };
42 
43 int main()
44 
45 {
46 
47 A a1(10);
48 
49 //用a1初始化a2
50 
51 A a2(a1);
52 
53 a2.show();
54 
55 A a3=a1;//用a1初始化a3
56 
57 a3.show();
58 
59 return 0;
60 
61 }

 

浅拷贝----带用系统默认的拷贝构造函数 只拷贝数据的值

危害:在有指针变量的时候,它只能拷贝一个地址,一旦其中的某个对象将申请的空间释放,其他对象的指针成员都没有值了。一般只允许在不进行内存空间的情况下可用。

深拷贝----调用自己写的拷贝函数

在有指针成员变量的时候,直接在拷贝构造函数中为改指针成员申请空间

String ----处理字符串的

 

    --by   吴尚奇    Dervil_box    2014/05

 

 

 

 

 

posted @ 2014-05-22 22:57  一页书_Devil_box  阅读(148)  评论(0编辑  收藏  举报