初始化列表(包括成员对象初始化)

初始化列表 ( 推荐 ) :
  可以初始化任何类型的数据, 不管是不是普通类型还是对象,都建议用.
  不再需要在构造器中赋值了, 而且初始化列表比构造函数要早执行.
  成员初始化次序取决于成员在类中的声明次序.

当类成员有其它对象时,构造器内给对象赋值会触发成员对象的默认构造函数(无参数的),如果成员对象没有默认构造函数编译报错.
  所以有成员变量为对象这种场景下,要用 initializer list.

Source:https://github.com/farwish/unix-lab/blob/master/cpp/Initializer_list.cc

继承

复用的一种方式,还有上面介绍过的 "对象组合"(成员变量为其他对象)

私有属性只能由父类自己访问;受保护的属性可以由子类访问,别人都无法访问.

当实例化子类时,会先调用父类的构造函数,当父类没有默认构造函数时又没有初始化自己的构造函数时,编译报类似 "no matching function AA::AA( )",所以在子类中只能用 initializer list 对父类成员初始化.

析构的调用次序则反过来,先子类后父类.

Source: https://github.com/farwish/unix-lab/blob/master/cpp/Extends.cc

函数重载(Function overload)和默认参数(Default argument)

同名函数通过拥有不同的参数表实现重载. void print( );   void print ( int i )

默认参数是在头文件中给原型的默认参数值,唯一的好处是某些情况下少打字;但是在调用时容易造成阅读困难,另外也不安全,如果我们不 include 头文件而是自己写一个函数声明,把默认参数值设为其它的,那么就和设计者的意图不一样。所以建议不使用 Default argument 如 void f (int i , int j = 10);

内联函数(Inline functions)

当函数前面有 inline 时,它就是一个 declaration,而不再是 defination,因此不需要担心重复定义的问题。

内联函数的 body 放在头文件里就可以了,不需要 .cpp 文件,和传统的一个 .h 对应一个 .cpp 不同。

因为内联函数有类型检查,因此比做同样事情的宏要好。

( 使用场合:函数只有2~3行的,需要重复调用的;不适合的:函数比较大,递归 )

成员函数在 class 声明时如果给出了 body,那么这些都是 inline 函数,只要有一个头文件就够了。

另一种写法是保持 class 声明干净,而为单独实现的成员函数前面加 inline.

Source: https://github.com/farwish/unix-lab/blob/master/cpp/Inline.h

Source: https://github.com/farwish/unix-lab/blob/master/cpp/Inline_main.cc

const; 不可修改的对象(对象成员)

成员函数 const 的用法:

在声明和定义的地方要一起用.

  int getData( ) const;

  int getData( ) const { return data }

不修改数据的成员函数应该被定义为 const.

如果类有 const 成员变量 或者 实例一个 const 对象,那么一定要在 initialize list 里面初始化变量,否则编译无法通过,因为后面无法修改它 (成员变量)。

func( ) { } 和 func( ) const { } 是不一样的,它们构成重载( overload ),因为它们相当于是 func( A* this ) 与 func( const A* this ),参数表不一样。

Source: https://github.com/farwish/unix-lab/blob/master/cpp/Const_class.cc

引用(C++数据类型)

char c; char* p = &c; char& r = c;

本地变量或全局变量,必须有初始值,type& name = 'name'  

  int x = 3;

    int& y = x;            # 赋初值

   const int& z = x;  # z 不能做左值,但是可以通过修改 x 来修改 z

作为参数和成员变量时,可以没有初始值,因为它们会在构造对象时被调用者初始化,type& name;

    void f ( int& x )

  f ( y );      # 在函数调用时初始化

指针和引用的区别:

  引用不能为 null.              指针可以为 null.

  引用依赖另一个变量,是一个变量的别名.  指针独立于已存在的对象.

    引用不能指向一个新的地址.        指针可以更改指向不同的地址.

  cpp内存模型的复杂性体现在:三个地方放对象(堆,栈,全局数据区),访问对象的方式(变量放对象,指针访问,引用访问)。

Source: https://github.com/farwish/unix-lab/blob/master/cpp/Reference.cc

引用再研究

引用作为类的成员时,声明时没有办法给初始值,因为它需要和另外一个变量捆绑在一起,作为别名;所以必须在构造函数的 initializer list 里初始化。

函数可以返回一个引用,但不能引用本地变量。

参数前的 const 的引用,const 保证不被修改,引用使传参高效,好处是函数中不用使用 * 号。

参数传引用,这说明参数是一个可以做左值的东西,传参不能使用变量非const的表达式。

  void func(int &); func(i * 3); // error:invalid initialization of non-const reference of type 'int&' from a temporary of type 'int'   error: in passing argument 1 of 'void f (int &)'

  void func(const int&); int i = 3; func(i * 3); // 区别仅在于参数是const的,正确输出9

不能对函数返回的对象做左值,编译会报错,error: using temporary as lvalue [-fpermissive]。

Source: https://github.com/farwish/unix-lab/blob/master/cpp/Reference_2.cc

向上造型(Upcasting)

子类的对象当做父类的对象来看,叫做向上造型,因为一般习惯把父类画在上面;Upcasting 一定是安全的,最多子类拥有的被无视。

父类的对象当做子类的对象看,叫做向下造型,Downcasting 有风险,因为父类不一定拥有子类的东西。

类型转换和造型的区别,类型转换原来的值转换完就变了,而造型数据没变,子类的对象还是子类的对象,只是看待的眼光不一样。

Persion John('JOHN');

Animal* p = &John;  // Upcast,  因为Person是Animal的一种, 但反过来就是 Downcast

Animal& q = John;   // Upcast

多态性(polymorphism):Upcast 和 Dynamic binding 两个条件构成多态性

Upcast: 把派生类当做基类使用。

Dynamic binding: 调用对象的函数。

  (Static binding: 调用代码写明的函数)

/**
* 通用函数,对任何 Shape 和其子类都通用.
*
* 动态绑定,调用的 render 在运行时决定:
* p 有一个静态类型和动态类型,如果 p 的 render 函数是 virtual 的,那么是动态绑定,不是 virtual 则是静态绑定。
* 所以动态绑定还是静态绑定取决于 render 函数,而不是对象 p;如果我们调用的是 move 函数,那么就是静态绑定。
*/
void render(Shape* p)
{
p->render();
}

Source: https://github.com/farwish/unix-lab/blob/master/cpp/Polymorphism.cc

虚 析构函数

Shape的析构不是 virtual 时,默认是静态绑定,delete p 时,只有 Shape 的析构会被调用,Ellipse 的不会调用。

Shape的析构是 virtual 时,表示动态绑定,delete p 时,会先调子类的析构,在调父类的析构。

  Shape* p = new Ellipse(100.0, 110.0);
    delete p;

其它 OOP 语言默认就是 virtual 的,也就是动态绑定的,而C++默认是静态绑定的,动态绑定需要手动加 virtual。

如果一个类里有一个 virtual 函数,它的析构函数就必须是 virtual 的。

如果父类和子类有名字相同、参数表相同的 virtual 函数,那么子类成员函数就对父类构成了重写/覆盖。

子类成员函数中调用父类的同名函数用 Base::func( ) 的方式。

父类里有两个 virtual 的重载(overload)函数,那么子类里也要实现两个 overloaded 的函数,否则另一个函数会发生 name hidden,只有 C++ 会发生函数的隐藏。

Source: https://github.com/farwish/unix-lab/blob/master/cpp/Polymorphism.cc

拷贝构造

拷贝构造的唯一形式:T::T(const T&)

拷贝构造什么时候被调用?
    1.用对象进行初始化时,Person p = p1 或 Person p(p1),这两种写法相同,注意它不是 assignment 而是 initialization (因为变量前有类型)。
    2.调用一个函数,函数的参数是一个对象时,void func(Person p);
    3.用返回对象的函数返回值进行初始化。

Construction vs Assignment
  每个对象只能构造一次,每个对象应该被析构一次,
  对象一旦被构造,它可以是被赋值的目标,前头有类型就是 initialization,没有类型就是 assignment.

Copy constructor guidelines
  写一个类就先写三个函数 default constructor, virtual distructor, copy constructor。
  如果确实不需要拷贝构造,那么就声明为私有,不建议这么做,限制了很多事不能做。

Source: https://github.com/farwish/unix-lab/blob/master/cpp/Copy_constructor.cc

静态对象

static两个基本的含义:

  静态存储,本地变量是static,这个本地变量具有持久存储(事实上static的本地变量就是全局变量)。

  名字可见性,全局变量、函数的static,那么这个全局变量、函数只在当前文件中可用。

static 在 C++ 中的使用:

  静态本地变量 - 持久存储。

    静态成员变量 - 所有对象间共享。

  静态成员函数 - 所有对象间共享,它只能访问静态成员变量。

    对象是静态的 - 除了遵守两个基本法则(存储、可见性),保证只构造析构一次。

静态初始化的依赖

  多个 cpp 文件都有自己的全局变量的情况,没人保证初始化顺序先后;

    如果一个变量的初始化依赖另一个变量的值作为参数,那么需要先初始化那另一个变量,但是跨文件的初始化是不存在的。所以解决方案是,1. 别这么干。 2. 逻辑上许可的话,把所有有依赖的全局变量放到一个地方。

Source:https://github.com/farwish/unix-lab/blob/master/cpp/Static_members.cc

运算符重载(Overloading Operators) - 基本规则

  运算符允许通过自己定义 function 来重载。

  

  只有已存在的运算符可以被重载,不能对类和枚举重载,必须保持操作数个数(如加法需要两个操作数),必须保证优先级。

  使用 operator 关键字作为函数名字,如重载 * 号,就是 operator * (...)

  可以作为成员函数,const String String::operator + (const String& that); 需要两个操作数,因为有默认参数 this 作为第一个,所以再只需要一个。

  可以是全局函数,const String operator + (const String& r, const String& l); 这时参数表需要两个参数。

  Integer x(1), y(5), z;

  x + y; ====> x.operator+(y);  这里的 x 就是receiver,receiver 决定 operator 用哪个。

  z = x + y; 可以。

  z = x + 3; 可以。

  z = 3 + y;  编译通不过。

  Tips:做成成员函数还是函数?

    单目的运算符应该做成是成员的,但非强制。

    = ( ) [] -> ->* 必须是成员的。

    赋值运算符应该做成是成员的。

    所有其它二元操作符作为非成员的。

原型

  参数传递:如果是只读的,那么传 const 的“引用”,不修改算子的成员函数加 const,全局函数可能两个都加或者又一个不加 const。

  返回值:1.决定了是对自己进行了修改还是返回了新对象; 2.制造出的新对象是不是可以做左值;

  运算符原型

  

  

Link:http://www.cnblogs.com/farwish/p/8099721.html

[Cpp] 面向对象程序设计 C++的更多相关文章

  1. 面向对象程序设计-C++ Stream & Template & Exception【第十五次上课笔记】

    这是本门<面向对象程序设计>课最后一次上课,刚好上完了这本<Thinking in C++> :) 这节课首先讲了流 Stream 的概念 平时我们主要用的是(1)在屏幕上输入 ...

  2. {key}面向对象程序设计-C++ polymorphism 【第十三次上课笔记】

    Peronal Link: http://segmentfault.com/a/1190000002464822 这节课讲了本门课程 面向对象程序设计中最为重要的一个部分 - 多态 /******** ...

  3. [.net 面向对象程序设计深入](8)认识.NET Core

    [.net 面向对象程序设计深入](8)认识.NET Core  1,概述          .NET 经历14年,在Windows平台上的表现已经相当优秀,但是“跨平台.开源”却是其痛点,从16年开 ...

  4. (C/C++学习笔记) 十七. 面向对象程序设计

    十七. 面向对象程序设计 ● 面向对象程序设计的基本概念 ※ 类实际上是一种复杂的数据类型,它不仅包含不同类型的数据,还包含对这些数据的一些必要的操作. 而对象则是这种复杂的数据类型的一个变量. 类是 ...

  5. 面向对象程序设计_Task5_Calculator1.5.0

    The 3rd part of the Calculator program _ FILE I/O 题目链接:第五次作业(计算器第三步) github链接:Calculator_1.5.0 第五次作业 ...

  6. C++ Primer笔记14_面向对象程序设计

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/scottly1/article/details/31371611 OOP概述 面向对象程序设计(ob ...

  7. c++面向对象程序设计 谭浩强 第二章答案

    类体内定义成员函数 #include <iostream> using namespace std; class Time { public: void set_time(); void ...

  8. 《挑战30天C++入门极限》理解C++面向对象程序设计中的抽象理论

        理解C++面向对象程序设计中的抽象理论 很多书在一开始就开始学习josephus问题,为了让大家前面学起来较为容易我把前面涉及到此问题的地方都故意去掉了,现在我们已经学习过了结构体和类,所以放 ...

  9. [.net 面向对象程序设计深入](0) 开篇

    [.net 面向对象程序设计深入](0)开篇        [.net 面向对象编程基础]和 [.net 面向对象程序设计进阶]在15年底写完了,群里也加进来不少热爱学习的小伙伴.让我深切感受到在这个 ...

随机推荐

  1. 51 Nod 1027 大数乘法【Java大数乱搞】

    1027 大数乘法 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 给出2个大整数A,B,计算A*B的结果. Input 第1行:大数A 第2行:大数B (A,B的长度  ...

  2. [51nod1684]子集价值

    lyk最近在研究位运算. 它发现除了xor,or,and外还有很多运算. 它新定义了一种运算符"#". 具体地,可以由4个参数来表示. ai,j表示 i#j. 其中i,j与a的值均 ...

  3. 2017西安网络赛 F

    f(cos(x))=cos(n∗x) holds for all xx. Given two integers nn and mm, you need to calculate the coeffic ...

  4. HDFS(数学题)

    题目连接:http://acm.tju.edu.cn/toj/showp.php?pid=4119 4119.   HDFS Time Limit: 5.0 Seconds   Memory Limi ...

  5. MySQL的ibdata1文件占用过大

    处理MySQL的ibdata1文件过大问题 本人遇到一次在安装zabbix监控的时候,yum安装的MySQL数据库,后面用了一段时间发现data目录下的ibdata1的空间特别大,反而我的zabbix ...

  6. 配置web.xml文件用于配置tomcat

    <Context path = "/myweb" docBase = "E:\workspace1\myweb\WebRoot" reloadable = ...

  7. vue安装babel依赖报错

    刚刚因为一些原因把依赖包删除,重新install了一下,结果报错 deprecate babel-preset-es2015@* ???? Thanks for using Babel: we rec ...

  8. cesium编程入门(七)3D Tiles,模型旋转

    cesium编程入门(七)3D Tiles,模型旋转 上一节介绍了3D Tiles模型的位置移动,和贴地的操作,这一节来聊一聊模型的旋转, 参考<WebGl编程指南>的第四章 假设在X轴和 ...

  9. MFC中自定义消息

    在头文件stdafx.h中增加一个自定义消息宏 #define WM_USER_THREADEND WM_USER + 1 在于增加新消息的窗口或对话框类的头文件中增加一个回调函数声明 afx_msg ...

  10. MLlib--GBDT算法

    转载请标明出处http://www.cnblogs.com/haozhengfei/p/8b9cb1875288d9f6cfc2f5a9b2f10eac.html GBDT算法 江湖传言:GBDT算法 ...