zoukankan      html  css  js  c++  java
  • c++面向对象 —— 类和对象

    类和对象

    类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法。类中的数据和方法称为类的成员。函数在一个类中被称为类的成员。

    一、类定义

    实际上并没有定义任何数据,但它定义了类的名称意味着什么,也就是说,它定义了类的对象包括了什么,以及可以在这个对象上执行哪些操作

    类定义是以关键字 class 开头,后跟类的名称。类的主体是包含在一对花括号中。类定义后必须跟着一个分号或一个声明列表。

    class Box
    {
       public:
          double length;   // 盒子的长度
          double breadth;  // 盒子的宽度
          double height;   // 盒子的高度
    };

    关键字 public 确定了类成员的访问属性。在类对象作用域内,公共成员在类的外部是可访问的。您也可以指定类的成员为 private 或 protected

     二、定义c++对象

    对象是根据类来创建的。声明类的对象,就像声明基本类型的变量一样

    Box Box1;          // 声明 Box1,类型为 Box
    Box Box2;          // 声明 Box2,类型为 Box

    对象 Box1 和 Box2 都有它们各自的数据成员。

    三、访问数据成员

    使用直接成员访问运算符 (.) 来访问

    #include <iostream>
     
    using namespace std;
     
    class Box
    {
       public:
          double length;   // 长度
          double breadth;  // 宽度
          double height;   // 高度
    };
     
    int main( )
    {
       Box Box1;        // 声明 Box1,类型为 Box
       Box Box2;        // 声明 Box2,类型为 Box
       double volume = 0.0;     // 用于存储体积
     
       // box 1 详述
       Box1.height = 5.0; 
       Box1.length = 6.0; 
       Box1.breadth = 7.0;
     
       // box 2 详述
       Box2.height = 10.0;
       Box2.length = 12.0;
       Box2.breadth = 13.0;
     
       // box 1 的体积
       volume = Box1.height * Box1.length * Box1.breadth;
       cout << "Box1 的体积:" << volume <<endl;
     
       // box 2 的体积
       volume = Box2.height * Box2.length * Box2.breadth;
       cout << "Box2 的体积:" << volume <<endl;
       return 0;
    }

    结果:

    Box1 的体积:210
    Box2 的体积:1560

    私有的成员和受保护的成员不能使用直接成员访问运算符 (.) 来直接访

    四、类对象详解

    类成员函数 类的成员函数是指那些把定义和原型写在类定义内部的函数,就像类定义中的其他变量一样。
    类访问修饰符 类成员可以被定义为 public、private 或 protected。默认情况下是定义为 private。
    构造函数 & 析构函数 类的构造函数是一种特殊的函数,在创建一个新的对象时调用。类的析构函数也是一种特殊的函数,在删除所创建的对象时调用。
    C++ 拷贝构造函数 拷贝构造函数,是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。
    C++ 友元函数 友元函数可以访问类的 private 和 protected 成员。
    C++ 内联函数 通过内联函数,编译器试图在调用函数的地方扩展函数体中的代码。
    C++ 中的 this 指针 每个对象都有一个特殊的指针 this,它指向对象本身。
    C++ 中指向类的指针 指向类的指针方式如同指向结构的指针。实际上,类可以看成是一个带有函数的结构。
    C++ 类的静态成员 类的数据成员和函数成员都可以被声明为静态的。

    补充:

    1.  this指针的理解

     2在类的外面,其实也可以用指针访问类内部的私有成员

    #include <iostream>
    using namespace std;
    
    class a    // 定义了类a
    {
        long a0;   // 定义私有成员 a0
        public:
        a(long b)
        {
            a0=b;
        }
        void geta()
        {
            cout<<a0<<endl;
        }
    };
    int main()
    {
        a b(5);          // 定义对象b,并给 b 中的 a0 赋初值
        long *p;
        p=(long*)&b;     // 令指针 p 指向 b 中前 4 个字节,在这里相当于指向 a0
        b.geta();        // 用内部函数访问 a0
        cout<<*p<<endl;  // 在外部直接访问 a0
        *p=8;            // 在外部改变 a0 的值
        b.geta();        // 输出改变后的结果
        cout<<*p<<endl;
        return 0;
    }

     使用这种方法虽然可以用于基于类的多态原则的一些程序开发,但违反了类的封装原则,在使用指针的类中也极不安全,所以不建议使用

    3.

    C++ 中的 struct 对 C 中的 struct 进行了扩充,它已经不再只是一个包含不同数据类型的数据结构了,它已经获取了太多的功能。

    struct 能包含成员函数吗? 能!

    struct 能继承吗? 能!!

    struct 能实现多态吗? 能!!!

    既然这些它都能实现,那 struct 和 class 还能有什么区别?

    最本质的一个区别就是默认的访问控制,体现在两个方面:

    1)默认的继承访问权限。struct是public的,class是private的。

    你可以写如下的代码:

    struct A
    {
        char a;
    };
    struct B : A
    {
        char b;
    };

    这个时候 B 是 public 继承 A 的。

    如果都将上面的 struct 改成 class,那么 B 是 private 继承 A 的。这就是默认的继承访问权限。

    所以我们在平时写类继承的时候,通常会这样写:

    struct B : public A

    就是为了指明是 public 继承,而不是用默认的 private 继承。

    当然,到底默认是 public 继承还是 private 继承,取决于子类而不是基类。

    我的意思是,struct 可以继承 class,同样 class 也可以继承 struct,那么默认的继承访问权限是看子类到底是用的 struct 还是 class。如下:

    struct A{}; 
    class B : A{}; //private继承
    struct C : B{}; //public继承

    2)struct 作为数据结构的实现体,它默认的数据访问控制是 public 的,而 class 作为对象的实现体,它默认的成员变量访问控制是 private 的。

    注意我上面的用词,我依旧强调 struct 是一种数据结构的实现体,虽然它是可以像 class 一样的用。我依旧将 struct 里的变量叫数据,class 内的变量叫成员,虽然它们并无区别。

    其实,到底是用 struct 还是 class,完全看个人的喜好,你可以将你程序里所有的 class 全部替换成 struct,它依旧可以很正常的运行。但我给出的最好建议,还是:当你觉得你要做的更像是一种数据结构的话,那么用 struct,如果你要做的更像是一种对象的话,那么用 class。

    当然,我在这里还要强调一点的就是,对于访问控制,应该在程序里明确的指出,而不是依靠默认,这是一个良好的习惯,也让你的代码更具可读性。

    说到这里,很多了解的人或许都认为这个话题可以结束了,因为他们知道 struct 和 class 的“唯一”区别就是访问控制。很多文献上也确实只提到这一个区别。

    但我上面却没有用“唯一”,而是说的“最本质”,那是因为,它们确实还有另一个区别,虽然那个区别我们平时可能很少涉及。那就是:“class” 这个关键字还用于定义模板参数,就像 “typename”。但关键字 “struct” 不用于定义模板参数。这一点在 Stanley B.Lippman 写的 Inside the C++ Object Model 有过说明。

    问题讨论到这里,基本上应该可以结束了。但有人曾说过,他还发现过其他的“区别”,那么,让我们来看看,这到底是不是又一个区别。还是上面所说的,C++ 中的 struct 是对 C 中的 struct 的扩充,既然是扩充,那么它就要兼容过去 C 中 struct 应有的所有特性。例如你可以这样写:

    struct A //定义一个struct
    {
        char c1;
        int n2;
        double db3;
    };
    A a={'p',7,3.1415926}; //定义时直接赋值

    也就是说 struct 可以在定义的时候用 {} 赋初值。那么问题来了,class 行不行呢?将上面的 struct 改成 class,试试看。报错!噢~于是那人跳出来说,他又找到了一个区别。我们仔细看看,这真的又是一个区别吗?

    你试着向上面的 struct 中加入一个构造函数(或虚函数),你会发现什么?

    对,struct 也不能用 {} 赋初值了。

    的确,以 {} 的方式来赋初值,只是用一个初始化列表来对数据进行按顺序的初始化,如上面如果写成 A a={'p',7}; 则 c1,n2 被初始化,而 db3 没有。这样简单的 copy 操作,只能发生在简单的数据结构上,而不应该放在对象上。加入一个构造函数或是一个虚函数会使 struct 更体现出一种对象的特性,而使此{}操作不再有效。

    事实上,是因为加入这样的函数,使得类的内部结构发生了变化。而加入一个普通的成员函数呢?你会发现{}依旧可用。其实你可以将普通的函数理解成对数据结构的一种算法,这并不打破它数据结构的特性。

    那么,看到这里,我们发现即使是 struct 想用 {} 来赋初值,它也必须满足很多的约束条件,这些条件实际上就是让 struct 更体现出一种数据机构而不是类的特性。

    那为什么我们在上面仅仅将 struct 改成 class,{} 就不能用了呢?

    其实问题恰巧是我们之前所讲的——访问控制!你看看,我们忘记了什么?对,将 struct 改成 class 的时候,访问控制由 public 变为 private 了,那当然就不能用 {} 来赋初值了。加上一个 public,你会发现,class 也是能用 {} 的,和 struct 毫无区别!!!

    做个总结,从上面的区别,我们可以看出,struct 更适合看成是一个数据结构的实现体,class 更适合看成是一个对象的实现体。

  • 相关阅读:
    PHP 开发 APP 接口 --Redis篇
    PHP 开发 APP 接口--静态缓存篇
    PHP 开发 APP 接口 --JSON、XML结合篇
    PHP 开发 APP 接口 --JSION篇
    PHP 开发 APP 接口--XML篇
    程序员必须掌握的600个英语单词
    Memcache
    伪静态
    ob缓冲
    函数的使用顺序---TABLES,USING,CHANGING
  • 原文地址:https://www.cnblogs.com/expedition/p/11355711.html
Copyright © 2011-2022 走看看