学习笔记之类(三)

来源:互联网 发布:短信群发源码 编辑:程序博客网 时间:2024/06/06 17:28

以下内容为Hughen个人学习C++ Primer Plus(第6版)后所写,欢迎一起探讨学习。

今天看书,非常意外的收获到一句话。Stephen Prata在讲到关于自定义的一个向量类,给予一个起始和终点位置,让计算机自己去找寻它们之间的路该怎么走,并算出走了多少步。他做了三组数据的输出,结果大不相同,电脑随机的路子,同一个距离,相差甚远,最后作者这样说:“如果发现自己在随机漫步时,请保持自信,迈大步走。虽然在蜿蜒前进的过程中仍旧无法控制前进的方向,但至少会走的远一点。”

看了这段话,深有感触。曾经自以为是,以为C++学的很好的我,在拜读了C++ Primer Plus之后发现,自己知道的东西太浅了,不及C++精华的百分之一,所以最近努力恶补欠缺的东西,一切又好像回到了那个为了理想奋斗的年代。我不知道成功究竟离我有多远,但是我相信他离我的距离正在越来越短。(可能这是一个复杂的算法,我无法确切的估算出时间复杂度,但是我深信,迟早我会return)

好了,言归正传,继续复习……

面向对象编程(OOP)的特性

  • 抽象;
  • 封装和数据隐藏;
  • 多态;
  • 继承;
  • 代码的可重用性。
为了将这些特性在C++体现出来,类(class)就诞生了。我是从C语言开始学的,习惯了面向过程的语言,在C++上或多或少有点体现,显得难以摆脱这种特性。书上说:“采用OOP方法时,首先从用户的角度考虑对象——描述对象所需的数据记忆描述用户与数据交互所需的操作。完成对接口的描述后,需要确定图和实现接口和数据存储。最后,使用新的设计方案创建出程序。”看到这其实你还是不知道该怎么做,最直接的做法是直接拉你去做一个大项目(比如ERP,HRMS等等),你负责做底层,为上层提供基本的调用I/O接口亦或者更复杂的接口,比如涉及到效率问题的(多线程呀,共享数据呀等等这些),这样一个项目下来就应该知道什么是OOP了,至少我是这么认为的。

类(class

访问控制

C++提供三种访问控制方式,privateprotectedpublic三个。其中类默认的访问控制是private,但是结构体的默认访问类型是public。
在类设计中尽可能的将公有接口与实现细节分开。(接口与实现相分离)】
这里还有需要注意的地方就是,定义位于类声明中的函数都将自动成为内联函数,所以无需inline标记。当然也可以显示的声明某函数为内联函数,则需要在函数定义的时候,在函数头前面用inline限定符,但是在类声明中是无需用inline标记。内联函数的特殊规则要求,在每个使用它们的文件都对其进行定义,所以最简便的方式就是将定义放在定义类的头文件中。
至于在类的工作原理上,请看下图:

构造函数

使用构造函数有显式地调用和隐式地调用的区别,两种情况如下:
Stock s1 = Stock("Global Company", 1000, 23);       // 显式地调用构造函数Stock s2("Stock Company", 930, 81);                 // 隐式地调用构造函数
当然两种调用方式都能正常的初始化并构造一个Stock类。
说道这里,就还有一种构造函数——默认构造函数,大致长相如下:
Stock::Stock() {......}Stock::Stock(const string &co = "no company", int n = 0, double price = 0.0) {......}
上述代码的两个都是默认构造函数,但是因为默认构造函数只有一个,所以上述代码只能有一个存在。默认构造函数可以没有任何参数,如果有,则必须给所有参数都提供默认值。
当构造函数只有一个参数时,也可以这样初始化对象:
Stock::Stock(int n) {......}Stock p = 90;           // 合法代码
  • 提示:隐式地调用构造函数时,是不需要使用圆括号的。
  • 提示:因为构造函数构造出对象之前,对象是不存在的,因此构造函数被用来创建对象,而不能通过对象来调用。

析构函数

析构函数用于完成类的生存期到了时的内存释放工作,这个过程是编译器决定的,不应该在代码中显式地调用析构函数。
  • 如果创建的是静态的存储类对象,则析构函数将在程序结束时自动调用。
  • 如果创建的是自动存储类对象,则析构函数将在程序执行完代码块时自动被调用。
  • 如果对象是通过new创建的,则它将一直驻留在栈内存或自由存储区中,直到使用delete来释放内存时,其析构函数将自动被调用。
其实在这里还有一个关于临时创建的类调用析构函数的问题,比如:
Stock s1 = Stock("Microsoft Corporation", 1200, 37);s2 = Stock("NETC", 10, 629.1);
上面的第一条语句初始化,它创建有指定值的对象,可能会创建临时对象(当然也可能不会,这个是需要根据不同的编译来决定的);第二条语句是赋值语句,像这样的语句是肯定会在使用构造函数的时候创建一个临时变量,然后将这个临时变量复制给s2。
C++11支持使用“{”和“}”来初始化类变量,比如:
Stock pkone = {"One", 12, 370};Stock jock {"Sport Inc."};
注意:const类对象是无法调用不确定是否会修改类成员变量的函数,它只能调用const函数。
比如:
const Stock stk = Stock("Blue Blue Car");stk.show();           // 错误的调用,因为stk为const对象,show()不是const函数
要想让stk调用show()怎么办,我们需要将show()声明为
void show() const;

this指针

如果在我们的代码中用到了如下样式的函数声明,则需要用到this指针的帮助:
const Stock & topval(const Stock & s) const;
其内部实现应该为:
const Stock & topval(const Stock & s) const{if(s.var > var)return s;elsereturn *this;         // 注意,这里是*this,而不是this指针}

类作用域

类作用域意味着不能从外部直接访问类的成员,公有成员函数也是如此。也就是说,要调用公有成员函数,必须通过对象。
对于在类中使用常量,以下代码是不允许的:
class Frame{private:const int m_Switch = 25;            // 错误的声明double point[m_Switch];}
主要是因为声明类知识描述了对象的形式,并没有创建对象,所以不会给其分配存储空间。
但是在类中使用常量也不是没有办法,如下:
class Frame{private:enum {m_Switch = 25};// 使用static const int m_Switch = 25;也是可以的,因为静态变量不是存储在对象中double point[m_Switch];}
这里的m_Switch只是一个名称,在作用域为整个类的代码中遇到它时,就会被替换成25。






原创粉丝点击