类和对象

一、什么是对象
1、万物皆对象
2、程序就是一组对象,对象之间通过消息交换信息。数据代表信息。
3、怎么用计算机语言描述对象?"类"就是对对象的描述和抽象。对象就是类的具体化和实例化。

二、通过类描述对象
    通过类描述对象, 具体就是从两个方面描述"静态属性"和"动态属性", 也就是"属性" 和 "行为"两个方面。
    类就是从属性和行为两个方面对对象的描述。
三、面向对象程序设计(OOP)

            现实世 界>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 虚拟世界
               对象->抽象           -->                   抽象->对象
      (对现实世界中的各种存在             (用计算机语言抽象地描述对象,程序
    的对象进行分析提取完成抽象)            运行就形成了虚拟世界的对象)
        
                                      类是编译期的一个概念。对象是运行期的概念。
        
OOP是一种编程思想,是一种看待问题、解决问题的思维方式,和编程语言没有任何关系。面向过程的C语言完全可以以OOP的思维方式编程,只不过面向对象语言提供了类、继承、多态可以极大地方便OOP而已。

1、至少掌握一门OOP语言
2、精通一种面向对象的元语言,例如UML
3、研究设计模式
四、C++类基本语法
1、类的定义
class C_Student{
};

2、类的成员:成员变量--属性
3、类的成员:成员函数--行为
4、访问控制属性
(1)公有成员: public
(2)私有成员: private
(3)保护成员:protected 只有自己和自己的子类可以访问

注意:类的成员缺省访控属性为私有,而C++的结构体虽然已经允许拥有成员函数,但是结构体缺省访控属性为公有。


以下是类定义举例:

 1 /*
 2  * 文件名: s.h
 3  * 描述:类Student的声明
 4  */
 5 #ifndef _S_H
 6 #define _S_H
 7 #include <string>
 8 using namespace std;
 9 // 声明Student类
10 class Student {
11 public:
12     Student (const string& name = "", int age = 0);
13     void eat (const string& food);
14 private:
15     string m_name;
16     int m_age;
17 };
18 #endif // _S_H

 

 1 /*
 2  * 文件名:s.cpp
 3  * 描述:类Student的实现
 4  * */
 5 #include <iostream>
 6 using namespace std;
 7 #include "s.h"
 8 // 实现Student类
 9 Student::Student (const string& name /* = "" */,
10     int age /* = 0 */) : m_name (name),
11     m_age (age) {}
12 void Student::eat (const string& food) {
13     cout << m_name << "" << m_age << "" << food
14         << endl;
15 }

 

 1 /*
 2  *文件名: main.cpp
 3  *描述:
 4  * */
 5 #include "s.h"
 6 // 使用Student类
 7 int main (void) {
 8     Student s ("张飞", 25);
 9     s.eat ("包子");
10     return 0;
11 }

 

 

5、构造函数
构造函数没有返回类型(根本就是没有返回类型,返回类型绝对不要以为是void)。构造函数函数名称必须和类名称一样。当一个对象被创建是,构造函数会自动被执行,以完成对象的构造,构造函数参数来自构造实际参数。
构造函数定义语法:
class C_Name {

    ....
    
    类名 (形式参数表){
    ...
    }


};


6、构造函数可以通过构造参数实现重载。
7、如果一个类没有定义任何构造函数,那么编译器就会缺省地为其提供一个void参数构造函数,该构造函数对于基本类型的成员变量不做初始化,对于类类型的成员变量,是会调用其相应的类型的无参构造

8、对象的创建过程。
分配内存->调用构造函数->调用类类型成员的构造函数->构造函数代码

9、初始化表。写在构造函数名称和构造函数体之间的初始化列表。
class 类名称 {
    类名称(...) : 初始化表
    {
    构造函数体
    }
};

(1)如果类中有常量或者引用型的成员变量,必须通过初始化表对其初始化。(P.S.成员变量的定义是在构造函数构造对象的时候发生的。)

 1 /*
 2  *如果类中有常量或者引用型的成员变量,必须通过初始化表对其初始化。(P.S.成员变量的定义是在构造函数构造对象的时候发生的。)
 3  * */
 4 #include <iostream>
 5 using namespace std;
 6 int g_data = 1000;
 7 class A {
 8 public:
 9     A (void) : m_c (100), m_r (g_data) {
10         //m_c = 100;//ERROR
11         //m_r = g_data;//ERROR
12     }
13     void print (void) {
14         cout << m_c << ' ' << m_r << endl;
15     }
16 private:
17     const int m_c;
18     int& m_r;
19 };
20 int main (void) {
21     A a;
22     a.print ();
23     return 0;
24 }

 

 

(2)成员变量的初始化顺序仅与其被声明的顺序有关,而于初始化表的顺序无关。成员变量之间应该尽可能减少相互依赖(p.s这叫做耦合),因为初始化顺序很可能影响相互依赖的成员。


(post script:注意严格区别"初始化语句"和"赋值语句"
 int a = 0;//初始化语句,"="为初始化操作符
 int b ;
 b = 0;//赋值语句,"="为赋值操作符
 )


10、类定义语法分为声明部分和实现部分。我们往往将类的声明和实现分开书写。
声明部分:class C_Name {/*这里面的都应该是声明语句。包括成员对象(简单对象,复杂对象),成员函数。*/};

 

 



五、this指针
(p.s.this指针不是类的成员变量。this是成员函数缺省的形式参数)
1、一般而言,在类的构造函数或者成员函数中,关键字this表示一个指针,对于构造函数而言,this指向正在被构造的对象,对于成员函数而言,this指向调用该函数的对象。
2、this指针的用途
(1)在类的内部,可以用this对成员变量加以区分。
 (2) 在成员函数中返回调用对象自身。
 (3) 在成员函数内部通过参数向外界传递调用对象自身,以实现对象间交互。

老 -问题-> 学

师 <-答案- 生

 1 /*
 2  * this指针举例
 3  *
 4  *老 -问题-> 学
 5 <p> *师 <-答案- 生</p> * 
 6  */
 7 #include <iostream>
 8 using namespace std;
 9 class Student;
10 class Teacher {
11 public:
12     void educate (Student* s);
13     void reply (const string& answer) {
14         m_answer = answer;
15     }
16 private:
17     string m_answer;
18 };
19 class Student {
20 public:
21     void ask (const string& question, Teacher* t) {
22         cout << "问题:" << question << endl;
23         t->reply ("不知道。");
24     }
25 };
26 void Teacher::educate (Student* s) {
27     s->ask ("什么是this指针?", this);
28     cout << "答案:" << m_answer << endl;
29 }
30 int main (void) {
31     Teacher t;
32     Student s;
33     t.educate (&s);
34     return 0;
35 }

 

 

C++不允许如下交叉类:
class A {
  B m_b;
};
class B {
  A m_a;
};
sizeof (A) ?
class C {
  C m_c;
};
但是可以有这样的交叉:
class B;
class A{
    B & m_b;//或者B * m_b;
};
class B{
    A & m_a;//或者A * m_a;
};
class C{
    C *m_c;//或者C& m_c;
};

 


六、常函数与常对象
1.如果在一个类的成员函数的参数表后面加上const关键字,那么这个成员函数就被称为常函数,常函数的this指针是一个常指针。在常函数内部无法修改成员变量,除非该变量具有mutable属性。而且在常函数内部也无法调用非常函数。
2.常对象:拥有const属性的对象,对象引用或指针。
常对象只能调用常函数。
同型的常函数和非常函数可以构成重载关系(因为他们的形式参数确实不一样,一个是常指针this,    一个是普通指针this)。常对象调用常版本,非常对象调用非常版本。如果没有非常版本,非常对象也可以调用常版本。

 1 /*
 2  *常函数与常对象
 3  * */
 4 #include <iostream>
 5 using namespace std;
 6 class A {
 7 public:
 8 //    void bar (void) {
 9 //        cout << "非常bar" << endl;
10 //    }
11     void bar (void) const {
12         cout << "常bar" << endl;
13     }
14 //  void XXXbarYYY (A* this) {}
15     void foo (void) const {
16 //        m_i = 100;
17         const_cast<A*>(this)->m_i = 100;
18     }
19     void print (void) const {//const关键字是用来修饰缺省形式参数this的,也就是说本函数的this指针是常指针。
20         cout << m_i << endl;
21     }
22 //    _ZNK1A3fooEv (const A* this) {
23 //        const_cast<A*>(this)->m_i = 100;
24 //    }
25     int m_i;//mutable int m_i;//加上mutable修饰符后,常函数就可以修改成员变量m_i了。
26 };
27 void func (void) /*const*/ {}
28 int main (void) {
29     A a;
30     a.foo ();
31     a.print ();
32     const A& r = a;
33     r.bar ();
34 //    XXXbarYYY (&r); // const A*
35     a.bar ();
36 //    XXXbarYYY (&a); // A*
37     return 0;
38 }

 

理解下面三个const修饰符修饰的是谁?

const XXX 函数名 (const YYY yyy) const {//第一个const修饰返回类型
                        //中间的const修饰形式参数类型
      ...                //最后一个const修饰成员函数的缺省形式参数this.
}

 


七、析构函数
class 类名 {
  ~类名 (void) {//析构函数参数必须是void型,函数名称必须是~类名称
     析构函数体;
  }
};
当一个对象被销毁时自动执行析构函数。
局部对象离开作用域时被销毁,堆对象被delete时被销毁。
如果一个类没有定义任何析构函数,那么系统会提供一个缺省析构函数。缺省析构函数对基本类型的成员变量什么也不干,对类类型的成员变量,调用相应类型的析构函数。
一般情况下,在析构函数中释放各种动态分配的资源。
构造:基类->成员->子类
析构:子类->成员->基类

posted on 2015-08-19 03:40  來時的路  阅读(149)  评论(0编辑  收藏  举报