C++深入理解 面向对象部分

一、面向对象深入部分

  在前几天 360 笔试做下来,感觉自己会的难度还行,还没学过的就乱选了,算法题部分做出来运行结果也是对的,但是两个解答题一点都没见过,直接就跳过了,继续努力吧。最近又重新改了改简历,准备投个实习,秋招的继续投递。继续刷课程,现在开始学习面向对象重要特点和使用方法。

1. 继承和派生

1.1 继承和派生

  继承:在定义一个新的类 B 时,如果该类与某个已有的类 A 相似(指的是 B 拥有 A 的全部特点),那么就可以把 A 作为一个基类,把 B 作为基类的一个派生类(也称子类)。派生类是通过基类进行修改和扩充得到的。在派生类中,可以扩充新的成员变量和成员函数。派生类一旦定义,就可以使用,不依赖基类。
  派生类拥有基类的全部成员函数,不论 private, protected, public 。在派生类的各个成员函数中,不能访问基类的 private 成员。写法为

class 派生类名:public 基类名{};class Student{private:string Name;int age;public:bool IsThreeGood(){};void setName(const string & name);{Name = name;}// ...
};class UndergraduateStudent:public Student{private:int Department;public:bool IsThreeGood(){......}; // 覆盖bool CanBaoYan(){......};
};  // 派生类写法:类名 puclic 基类名class GraduateStudent:public Student{private:int Department;char mentorName[20];public:int CountSalary(){};
};

  派生类对象的体积,等于基类对象的体积,再加上派生类对象自己的成员变量的体积。派生类对象中,包含基类对象,而且基类对象的存储位置位于派生类对象新增的成员变量之前。例如,

#include <iostream>
#include <string>
using namespace std;class Student{private:string name;string id;char gender; // "F"代表女,"M"代表男int age;public:void printInfo();void setInfo(const string & name_, const string & id_,int age_, char gender_);string getName(){return name;}
};
void Student::printInfo(){cout << "name:" << name << endl;cout << "id:" << id << endl;cout << "gender:" << gender << endl;cout << "age:" << age << endl;
}
void Student::setInfo(const string & name_, const string & id_,int age_, char gender_){name = name_;id = id_;age = age_;gender = gender_;
}class UndergraduateStudent:public Student{  // 本科生类,继承了Student类private:string department; // 学生所属的系的名称public:void qualifiedForBaoyan(){ // 给予保研资格cout << "qulified for baoyan" << endl;}void printInfo(){// 不写的话,就会当作派生类自己的函数Student::printInfo(); // 调用基类的 printInfocout << "Department:" << department << endl;}void setInfo(const string & name_, const string & id_,int age_, char gender_, const string & department_){Student::setInfo(name_, id_, age_, gender_); // 调用基类的 setInfodepartment = department_;}
};int main(){UndergraduateStudent s2;s2.setInfo("Harry Potter", "118829212", 19, 'M', "Computer Science");cout << s2.getName() << " ";s2.qualifiedForBaoyan();s2.printInfo();return 0;
}

视频里有两个函数没有写,所以运行出来有问题,后来我自己补充上运行得到了结果,如下,

1.2 继承关系和复合关系

  继承是“是”的关系,复合是“有”的关系。举个例子,要写一个圆和点的类。圆里面有点,所以要写成复合关系,如下

class Point{double x, y;friend class Circle; // 因为 x,y是私有的
}class Circle{double r;Point center;  // 复合类
}

  复合关系的使用:比如有一个业主和狗管理信息情况,那就只能用复合关系来写,其中每个主人最多有10条狗,所以定义如下,

// 为“狗”类写一个“业主”类的对象指针;
// 为“业主”类设一个“狗”类的对象指针数组。
class Master; // Master 必须提前声明,不能先写 Master 类后写 Dog 类class Dog{Master * pm;
}
class Master{Dog * dogs[10];
}
// 这样两个类可以相互独立,也可以找到他们的关系

1.3 覆盖和保护成员

  覆盖:派生类可以定义一个和基类成员同名的成员,这叫覆盖。在派生类中访问这类成员时,缺省情况是访问派生类定义的成员。要在派生类中访问基类同名成员时,要使用作用域::。
  一般来说,基类和派生类不定义同名成员变量。
  类的保护成员,汇总如下,

  举个例子,

#include <iostream>
#include <string>
using namespace std;class Father{private: int Private;public: int Public;protected: Protected;
};
class Son:Father{void accessFather(){Public = 1;  // 可以Private = 1;  // 不可以Protected = 1;  // 可以,访问从基类继承的 protected 成员Son f;  // 没太理解f.Protected = 1; // 编译出错, f 不是当前对象}
}int main(){Father f;Son s;f.Public = 1; // 可以f.Private = 1; // 不可以f.Protected = 1; // 不可以s.Public = 1; // 可以s.Protected = 1; // 不可以s.Private = 1; // 不可以return 0;
}

1.4 派生类的构造函数

  举个例子,

#include <iostream>
#include <string>
using namespace std;class Bug{private:int legs;int color;public:int type;Bug(int nlegs, int ncolor);void printBug(){};
};
class flyBug: public Bug{int wings;public:flyBug(int nlegs, int ncolor, int nwings);
};
Bug::Bug(int nlegs, int ncolor){legs = nlegs;color = ncolor;
}
// 错误的 flyBug 构造函数
/*
flyBug::flyBug(int nlegs, int ncolor, int nwings){legs = nlegs;  // 不能访问color = ncolor; // 不能访问type = 1; // 可以wings = nwings; // 可以
}*/
// 正确的 flyBug 构造函数
flyBug::flyBug(int nlegs, int ncolor, int nwings):Bug(nlegs, ncolor){wings = nwings; // 可以
}int main(){flyBug fb(2, 3, 4);fb.printBug();fb.type = 1;// fb.Legs = 2;  // 错误,私有的return 0;
}

  在创建派生类的对象时,需要调用基类的构造函数:初始化派生类对象中从基类继承的成员。在执行一个派生类的构造函数之前,总是先执行基类的构造函数。
  调用基类构造函数的两种方式,

显示方式:在派生类的构造函数中,为基类的构造函数提供参数;derived::derived(arg_derived-list):base(arg_base-list)
隐式方式:在派生类的构造函数中,省略基类构造函数时,派生类的构造函数则自动调用基类的默认构造函数。

  派生类的析构函数被执行时,执行完派生类的析构函数后,自动调用基类的构造函数。例如

#include <iostream>
#include <string>
using namespace std;class Base{public:int n;Base(int i):n(i){cout << "Base " << n << " constructed" << endl;}~Base(){cout << "Base " << n << " destructed" << endl;}
};
class Derived: public Base{public:Derived(int i):Base(i){cout << "Derived constructed" << endl;}~Derived(){cout << "Derived destructed" << endl;}
};
int main(){Derived Obj(3);return 0;
}

  结果如下,

  包含成员对象的派生类的构造函数写法,如下

#include <iostream>
#include <string>
using namespace std;class Bug{private:int legs;int color;public:int type;Bug(int nlegs, int ncolor);void printBug(){};
};
class Skill{public:Skill(int n){}
};
class flyBug:public Bug{int wings;Skill sk1, sk2;  // 包含成员对象的派生类public:flyBug(int nlegs, int ncolor, int nwings);
};
flyBug::flyBug(int nlegs, int ncolor, int nwings):Bug(legs, color), sk1(5), sk2(color), wings(nwings){}

1.5 公有继承的赋值兼容规则

  public 继承的赋值兼容规则,

class base{};
class derived:public base{};
base b;
derived d;// 1) 派生类的对象可以赋值给基类对象
b = d; // d 里面有的内容拷贝到 b 中
// 2) 派生类的对象可以初始化基类引用
base & br = d; // 基类引用派生类包含的那一个部分
// 3) 派生类的对象地址可以赋值给基类指针
base * bp = & d; // 指针指向派生类包含的那一个部分(先存基类,再存派生类)
  1. 派生类的对象可以赋值给基类对象
    b = d; // d 里面有的内容拷贝到 b 中
  2. 派生类的对象可以初始化基类引用
    base & br = d; // 基类引用派生类包含的那一个部分
  3. 派生类的对象地址可以赋值给基类指针
    base * bp = & d; // 指针指向派生类包含的那一个部分(先存基类,再存派生类)
    如果不是public 就不成立了
      直接基类和间接基类的理解。B:A, C:B, D:C,多个继承,比较容易理解。
    ----------》派生类沿着类的层次自动向上继承它的间接基类。
    ----------》派生类成员包括:派生类自己的成员,直接基类的所有成员,所有间接基类的全部成员
    ----------》在声明派生类时,只需要列出它的直接基类就行
    ----------》构造函数执行从基类到最底类,由顶层开始。析构函数执行时,由底至顶

2. 虚函数和多态

2.1 虚函数和多态定义

  在类的定义中,前面有 virtual 关键字的成员函数就是虚函数。virtual 关键字只用在类定义里的函数声明时,写函数体时不用。构造函数和静态成员函数不能是虚函数。例如

// 虚函数可以参与多态,其他函数不能
class base{virtual int get();
};
int base::get(){}

多态的表现形式一,
----》派生类的指针可以赋给基类指针;
----》通过基类指针调用基类和派生类中的同名虚函数时:1) 若该指针指向一个基类的对象时,那么被调用是基类的虚函数;2) 若该指针指向一个派生类的对象,那么被调用的是派生类的虚函数。**这种机制就叫做多态。**举个例子,

class Base{public:virtual void someVirtualFunc(){}
};
class Derived: public Base{public:virtual void someVirtualFunc(){}
};int main(){Derived derived;Base *p = & derived;// 调用哪个虚函数取决于 p 指向哪种类型的对象// 指向的是 Derived 类对象的虚函数p -> someVirtualFunc();return 0;
}

多态的表现形式二,
----》派生类的对象可以赋给基类引用
----》通过基类引用调用基类和派生类中的同名虚函数时:1) 若该引用引用的是一个基类的对象,那么被调用的是基类的虚函数;2) 若该引用引用的是一个派生类的对象,那么被调用的是派生类的虚函数。这种机制也叫做多态。 举个例子,

class Base{public:virtual void someVirtualFunc(){}
};
class Derived: public Base{public:virtual void someVirtualFunc(){}
};int main(){Derived derived;Base & r = derived;// 调用哪个虚函数取决于 r 引用哪种类型的对象// 指向的是 Derived 类对象的虚函数r.someVirtualFunc();return 0;
}

  多态的简单示例,

#include <iostream>
#include <string>
using namespace std;class A{public:virtual void print(){cout << "A::print"<<endl;}
};
class B: public A{public:virtual void print(){cout << "B::print"<<endl;}
};
class D: public A{public:virtual void print(){cout << "D::print"<<endl;}
};
class E: public B{public:virtual void print(){cout << "E::print"<<endl;}
};int main(){A a; B b;   E e; D d;A * pa = & a; B * pb = & b;D * pd = & d; E * pe = & e;pa -> print(); // pa 是基类指针,多态pa = pb;pa -> print();pa = pd;pa -> print();pa = pe;pa -> print();return 0;
}


  
  多态的作用: 在面向对象的程序设计中使用多态,能够增强程序的可扩充性,即程序需要修改或增加功能的时候,需要改动和增加的代码较少。

2.2 多态实例:《魔法门之英雄无敌》

  游戏中有很多种怪物,每种怪物都有一个类与之对应,每个怪物就是一个对象。怪物能够互相攻击,攻击敌人和被攻击时都有相应的动作,动作是通过对象的成员函数实现的。
  游戏版本升级时,要增加新的怪物–雷鸟。如何编程才能使升级时的代码改动和增加量较小?
  基本思路:
----》为每个怪物类编写 Attack,FightBack 和 Hurted 成员函数
----》Attack 函数表现攻击动作,攻击某个怪物,并调用被攻击怪物的 Hurted 函数,以减少被攻击怪物的生命值,同时也调用被攻击怪物的 FightBack 成员函数,遭受被攻击怪物的反击。
----》设置基类 Creature, 使用怪物类都从基类派生而来
  
  
  非多态写法:

#include <iostream>
#include <string>
using namespace std;class Creature{protected:int power;   // 代表生命力int lifeValue;  // 代表生命值
};
class Deagon: public Creature{public:void Attack(Wolf* pWolf){// ... 表现攻击动作的代码pWolf -> Hurted(power);pWolf -> FightBack(this);}void Attack(Ghost* pGhost){// ... 表现攻击动作的代码pGhost -> Hurted(power);pGhost -> FightBack(this);  // 指向攻击发起者}void Hurted(int power){// ... 表现受伤的动作lifeValue -= power;}void FightBack(Wolf* pWolf){// ... 表现反击的动作pWolf -> Hurted(power / 2);}void FightBack(pGhost* pGhost){// ... 表现反击的动作pGhost -> Hurted(power / 2);}
};

  这样,有 n 中怪物,Deagon 类中就会有 n 个 Attack 成员函数,以及 n 个 FightBack 成员函数。对于其他类也是一样的。
  
  
  多态写法:

#include <iostream>
#include <string>
using namespace std;class Creature{protected:int power;   // 代表生命力int lifeValue;  // 代表生命值public:virtual void Attack(Creature * pCreature){}virtual void Hurted(int power){}virtual void FightBack(Creature * pCreature){}
};
class Dragon: public Creature{public:virtual void Attack(Creature * pCreature);virtual void Hurted(int power);virtual void FightBack(Creature * pCreature);
};
void Dragon::Attack(Creature * pCreature){// ... 表现攻击动作的代码pCreature -> Hurted(power);  // 多态pCreature -> FightBack(this);  // 多态
}
void Dragon::Hurted(int power){// ... 表现受伤的动作lifeValue -= power;
}
void Dragon::FightBack(Creature * pCreature){// ... 表现反击的动作pCreature -> Hurted(power / 2);  // 多态
}

  如果游戏升级,增加了新怪物。只要编写新类怪物,不需要在已有的类里为新怪物增加成员函数,已有的类可以原封不动。原理如下,

#include <iostream>
#include <string>
using namespace std;// 例如
Dragon dragon;    Wolf wolf;   Ghost ghost;
thunderBird Bird;
Dragon.Attack(& wolf);  // (1)
Dragon.Attack(& ghost);  // (2)
Dragon.Attack(& Bird);  // (3)

  根据多态的规则,上面的 (1), (2), (3) 进入到 Dragon::Attack 函数以后,能分别调用:Wolf::Hurted, Ghost::Hurted, thunderBird::Hurted.

2.3 多态实例:几何形体程序

  几何形体处理程序:输入若干个几何形体的参数,要求按面积排序输出。输出时要指明形状,

Input:
第一行是几何形体数目 n (不超过100).下面有 n 行,每行以一个字母 c 开头。
如 c 是 "R", 则代表一个矩形,本行后面跟着两个整数,分别是矩形的宽和高;
如 c 是 "C", 则代表一个圆形,本行后面跟着一个整数代表其半径;
如 c 是 "T", 则代表一个三角形,本行后面跟着三个整数,代表三条边长度;Output:
按面积从大到小依次输出每个几何形体的种类及面积。每行一个几何形体,输出格式为:
形体名称:面积Sample Input:
3
R 3 5
C 9
T 3 4 5Sample Output:
Triangle: 6
Rectangle: 15
Circle: 254.32

  实现如下,

#include <iostream>
#include <stdlib.h>
#include <math.h>using namespace std;class Shape{public:virtual double Area() = 0; // 纯虚函数virtual void printInfo() = 0;
};
class Rectangle: public Shape{public:double w, h;virtual double Area();virtual void printInfo();
};
class Circle: public Shape{public:double r;virtual double Area();virtual void printInfo();
};
class Triangle: public Shape{public:double a, b, c;virtual double Area();virtual void printInfo();
};
double Rectangle::Area(){return w * h;
}
void Rectangle::printInfo(){cout << "Rectangle:" << Area() << endl;
}
double Circle::Area(){return 3.14 * r * r;
}
void Circle::printInfo(){cout << "Circle:" << Area() << endl;
}
double Triangle::Area(){double p = (a + b + c) / 2.0;return sqrt(p * (p - a)*(p - b)*(p - c));
}
void Triangle::printInfo(){cout << "Triangle:" << Area() << endl;
}// 进入的是数组元素指针
int myCompare(const void * s1, const void * s2){double a1, a2;Shape ** p1; // s1, s2 是 void*, 不可写"*s1"来取得s1指向的内容Shape ** p2;p1 = (Shape **)s1; // s1, s2 指向 Shape 数组中的元素,数组元素的类型是 Shape*p2 = (Shape **)s2; // p1, p2 都是指向指针的指针,类型为 Shape**a1 = (*p1) -> Area(); // *p1 的类型是 Shape*, 是基类指针,故此句为多态a2 = (*p2) -> Area();if(a1 < a2)return -1;else if(a2 < a1)return 1;else return 0;
}Shape * pShapes[100];
int main(){int i; int n;Rectangle * pr; Circle * pc; Triangle * pt;cin >> n;for(i = 0; i < n; i++){char c;cin >> c;switch(c){case 'R':pr = new Rectangle();cin >> pr->w >> pr->h;pShapes[i] = pr;break;case 'C':pc = new Circle();cin >> pc->r;pShapes[i] = pc;break;case 'T':pt = new Triangle();cin >> pt->a >> pt->b >> pt->c;pShapes[i] = pt;break;}}qsort(pShapes, n, sizeof(Shape*), myCompare);for(i = 0; i < n; i++)pShapes[i]->printInfo();return 0;
}

  结果如下,

2.4 多态实例:Base 例子

  接下来对这个例子进行理解,

#include <iostream>
#include <stdlib.h>
#include <math.h>using namespace std;class Base{public:void func1(){func2()}; /* 解释如下void func1(){this->func2()}; // this 是基类函数,fun2是虚函数,所以是多态 */virtual void fun2(){cout << "Base::func2()" << endl};
};
class Derived: public Base{public:virtual void func2(){cout << "Derived: fun2()" << endl;}
};
int main(){Derived d;Base *pBase = &d;pBase -> fun1();return 0;
}

  接下来对这个例子进行理解,不过真想感叹一句,这个老师喝水是真滴 LiuPi,一大瓶水真的喝完了,一大瓶。。。看下面,

  吐槽完了继续理解,为什么输出的是 “Derived: fun2()”,注意 this 指针。注意,在非构造函数,非析构函数的成员函数中调用虚函数,是多态

  构造函数和析构函数中调用虚函数。在构造函数和析构函数中调用虚函数,不是多态。编译时即可确定,调用的函数是自己的类或者基类中定义的函数,不会等到运行时才决定调用自己的还是派生类的函数。例如,

  
  
  注意:派生类中和基类中虚函数同名同参数表的函数,不加 virtual 也自动成为虚函数
  
  

#include <iostream>
#include <stdlib.h>
#include <math.h>using namespace std;class myclass{public:virtual void hello(){cout << "hellp from myclass" << endl;};virtual void bye(){cout << "bye from myclass" << endl;}
};
class son:public myclass{public:// 注意:派生类中和基类中虚函数同名同参数表的函数,不加 virtual 也自动成为虚函数void hello(){cout << "hello from son" << endl;};// 注意 在构造函数和析构函数中调用虚函数,不是多态。son(){hello();};  // 虚函数~son(){bye();};  // 虚函数
};
class grandson: public son{public: // 虚函数,注意 在构造函数和析构函数中调用虚函数,不是多态。void hello(){cout << "hello from grandson" << endl;};void bye(){cout << "bye from grandson" << endl;};grandson(){cout << "constructing grandson" << endl;};~grandson(){cout << "distructing grandson" << endl;};
};int main(){grandson gson;son * pson;pson = &gson;pson -> hello();  // 多态return 0;
}

  结果如下,

3. 多态实现原理及其一些细节

3.1 多态实现原理

  “多态”的关键字在于通过基类指针或引用调用一个虚函数时,编译时不确定到底调用的是基类还是派生类的函数,运行时才确定,这叫 “动态联编”。有一个例子

class Base{public:int i;virtual void print(){cout << "Base:print" << endl;}
};
class Derived: public Base{public:int n;virtual void print(){cout << "Derived:print" << endl;}
};int main(){Derived d;cout << sizeof(Base) << ", " << sizeof(Derived);
}
// 输出结果为: 8, 12 为什么都多出了四个字节

  多态实现的关键,虚函数表
  每一个有虚函数的类(或有虚函数的类的派生类)都有一个虚函数表,该类的任何对象中都存放虚函数表的指针。虚函数表中列出了该类的虚函数地址。多出来的四个字节就是用来放虚函数表的地址的
  多态的函数调用语句被编译成一系列根据基类指针所指向的(或基类引用所引用的)对象中存在的虚函数表的地址,在虚函数表中查找虚函数地址,并调用虚函数。在理解,举个例子,

#include <iostream>
#include <stdlib.h>
#include <math.h>using namespace std;class A{public:virtual void Func(){cout << "A::Func" << endl;}
};
class B: public A{public:virtual void Func(){cout << "B::Func" << endl;}
};int main(){A a;A * pa = new B();pa -> Func();// 64 位程序指针为 8 字节long long * p1 = (long long *) & a;long long * p2 = (long long *) pa;* p2 = * p1; // a 虚函数表的地址覆盖掉 B 虚函数表的地址pa -> Func(); // 查虚函数表才知道,return 0;
}

  结果如下,

  指针赋予了程序访问任意地址空间的能力,对函数的任意字节进行修改,有助于提升使用效率。

3.2 虚析构函数、纯虚函数和抽象类

  虚析构函数:
  通过基类的指针删除派生类对象时,通常情况下只调用基类的析构函数。
------》但是,删除一个派生类的对象时,应该先调用派生类的析构函数,然后调用基类的析构函数。
  解决方法:把基类的析构函数声明为 virtual
------》派生类的析构函数可以 virtual 不声明
------》通过基类的指针删除派生类对象时,首先调用派生类的析构函数,然后调用基类的析构函数。
  一般来说,一个类如果定义了虚函数,则应该将析构函数也定义成虚函数。或者,一个类打算作为基类使用,也应该将析构函数定义成虚函数。
  注意:不允许以虚函数作为构造函数。举个例子,

class son{public:~son{cout << "bye from son" << endl;}
};
class grandson: public son{public:~grandson{cout << "bye from grandson" << endl;}
};int main(){son *pson;pson = new grandson();delete pson;return 0;
}

  输出:bye from son // 没有执行 grandson::~grandson(). 因此解决方法为,

class son{public:virtual ~son{cout << "bye from son" << endl;}
};
class grandson: public son{public:~grandson{cout << "bye from grandson" << endl;}
};int main(){son *pson;pson = new grandson();delete pson;return 0;
}

  输出:bye from grandson \r\n bye from son // 先执行 grandson::~grandson(),引起执行 son:: ~ son() .
  
  
  纯虚函数:没有函数体的函数:
  例如,

class A{private: int a;public:virtual void print() = 0;  // 纯虚函数void func(){cout << "func"; }
};

  抽象类:包含纯虚函数的类
----------》 抽象类只能作为基类来派生新类使用,不能创建抽象类的对象
----------》 抽象类的指针和引用可以指向由抽象类派生出来的类的对象
  例如,

A a;   // 错误的, A 是抽象类,不能创建对象
A * pa;  // 可以的,可以定义抽象类的指针和引用
pa = new A;  // 错误, A 是抽象类,不能创建对象

----------》 在抽象类的成员函数内可以调用纯虚函数,但是在构造函数或析构函数内部不能调用纯虚函数。(注意多态在不同形式下调用的情况)
----------》 如果一个类从抽象类派生而来,那么当且仅当它实现了基类中的所有纯虚函数,它才能成为非抽象类。
  具体例子,

#include <iostream>
#include <stdlib.h>
#include <math.h>using namespace std;class A{public:virtual void f() = 0; // 纯虚函数void g(){this -> f(); // 可以的,是多态}A(){ // f()}; // 错误的,在构造函数调用虚函数不是多态}
};
class B: public A{public:void f(){cout << "B:f()" << endl;}
};
int main(){B b;b.g();return 0;
}

  结果如下,

4. 总结

  这个老师是讲的真不错,逻辑清晰,按照说的复现不卡 BUG,不用浪费时间调,直接理解就行,真推荐想学习的也看看他的视频。最近这两天投了简历,弄了笔试,面试,结果不是特别理想。自己学习程度还不够,继续加油。而且这两天还重新改了下第二篇论文内容,算是改的自己感觉差不多了吧。说实话因为自身原因和 D S 原因,我现在对我的课题是真的不喜欢,论文就是不想改,看到就 EX 那种。第一篇论文老师让我从 3 月就改到 9 月,过程比较复杂,现在也还没投稿,从着急,劳累,痛苦到现在的淡然,之后的随缘,反正毕业就行。反正感觉现在总算有了学习的动力,继续弄下去。最近可能有点事,第三版就可能慢一点,也有可能很快就肝完了。

3.C++深入理解 面向对象部分2相关推荐

  1. 深入理解面向对象 -- 基于 JavaScript 实现

    我们在学习编程时,避免不了会接触一个概念,叫:面向对象编程(Object-oriented programming,缩写:oop) (不是搞对象那个对象哈),其实我们的编程方式,不止有面向对象,还有 ...

  2. 从C++到Java --理解面向对象是关键所在

    从C++到Java --理解面向对象是关键所在 本文将提供一个对这些概念的简明的解释,而不是提供一些深入的或者如何使用的问题.记住,这只是依据我对Java的经验带而提出的一些主要的差异. Java在虚 ...

  3. 4.C++深入理解 面向对象部分3

    C++深入理解 面向对象部分 一.C++流的控制 1.1 输入输出流相关的类   输入输出重定向例子, #include <iostream> using namespace std; i ...

  4. 2.C++深入理解 面向对象部分1

    C++深入理解 面向对象部分 一.补充知识   现在开始刷 北京大学 程序实际与算法三 视频面向对象部分学习,记录自己不懂的知识,这里以后打算学习 C++ 了,把这门语言吃透再学习新的,这里使用的运行 ...

  5. (自己收藏)全面理解面向对象的 JavaScript

    全面理解面向对象的 JavaScript 前天 by 资深编辑 WnouM 评论(3) 有2727人浏览 收藏 javascript 面向对象 对象 类 原型 < >猎头职位: 上海:Ju ...

  6. 深度理解面向对象的基础-抽象(一)

    前言: 面向对象这个词对于我们程序开发人员来说,应该都不陌生,我们总说开发要面向对象,但实际上在编写代码的过程中,很多人虽然实现了封装.继承.多态但却不是面向对象的程序设计,而是面向过程的实现逻辑,徒 ...

  7. 如何理解面向对象的封装、继承、多态

    如何理解面向对象的封装.继承.多态 面向对象可以说是一种对现实是事物的抽象,将一类事物抽象成一个类,类里面包含了这类事物具有的公共部分,以及我们对这些部分的操作,也就是对应的数据和过程. 面向对象思想 ...

  8. Java SE 008 理解面向对象程序设计 (Inside Object Oriented Programming)

    Java SE 008 理解面向对象程序设计 (Inside Object Oriented Programming) 前言:此笔记为圣思园张龙老师讲述的java视频课程笔记,自己看视频学习时记录的, ...

  9. 从哲学角度理解面向对象的思想

    "双语播放器"已在app store上架,欢迎大家前去下载(主要用于看电影,学英语,程序员一定要学好英语!) 这里是链接: https://itunes.apple.com/cn/ ...

最新文章

  1. 比特币再度遭遇资金“大逃离” 后市前景愈发摇摇欲坠
  2. shader 4 杂 一些和函数名词、数据结构
  3. 解决阿里云postfix无法发送邮件问题
  4. 牛客 - 牛半仙的妹子Tree(按询问分块+RMQ求LCA)
  5. Windows 服务(附服务开发辅助工具)
  6. Fifth scrum meeting - 2015/10/30
  7. linux下载python的地址_Linux下Python获取IP地址的代码
  8. WebApi接口访问异常问题。尝试创建“testController”类型的控制器时出错。请确保控制器具有无参数公共构造函数
  9. GPUImage源码解读之GPUImageFramebufferCache
  10. 文件大小超过配置限制(2560000),代码洞察功能不可用怎么办?
  11. RS485接口上的PTC
  12. linux制作grub启动u盘启动菜单,用u盘制作grub启动盘[来源不详]
  13. 怎样通过计算机修改蓝牙音箱,有线音箱怎么改蓝牙无线音箱 有线音箱改无线音箱方法介绍【详解】...
  14. 语音信号处理-概念(三):FBank特征、MFCC特征(梅尔频率倒谱系数)【由于二者蕴含信息较少,已不适合这个大数据时代。但有些任务由于其本身的特殊性质,还是会使用到MFCC谱。如情感语音转换任务】
  15. 书评与摘抄《经济学原理》
  16. C# 連接mysql,連接后顯示多個線程池
  17. 数据库连接10060_Navicat MySQL 数据库连接报:10060 “Unknow error” 错误 – DEFCON笔记...
  18. 身为程序员还看不懂UML类图? 一文带你零基础学会看UML类图!
  19. BZOJ2277 [Poi2011]Strongbox 【数论】
  20. 类型转换、强制类型转换

热门文章

  1. Type is unsupported, or the types of the items don‘t match field type in CollectionDef.
  2. 多示例学习 MIL(multiple instance learning) 理解
  3. PCB 电测试--测试点数自动输出到流程指示中(读取TGZ Stephdr文件)
  4. 10个用Console来Debug的高级技巧
  5. 智慧故事----每次进来看看都会有收获
  6. 网站防盗链就是那么简单
  7. domtoimage -- html转化为图片
  8. Linux主机SSH免密码登录设置
  9. 解决问题 WebDriverException: Message: unknown error: cannot find Chrome binary
  10. 深入探讨运维驱动的可监控性设计