客观世界中任何一个实物都可以看成一个对象 (object)。或者说,客观世界是由千千万万个对象组成的。任何一个对象都应当具有两个要素,即属性和行为,一个对象往往是由一组属性和一组行为构成的。例如,一台录影机是一个对象,它的属性是生产厂家、牌子、重量等,它的行为就是它的功能,例如可以给外界给他的信息进行录像、快进、快退等操作。在一个系统中的多个对象之间通过一定的渠道相互联系,要使某一个对象实现某一种行为,应当向它传入相应的消息。在C++中,每个对象都是由数据和函数这两部分组成的,函数是用来对数据进行操作的。
面向对象的三个基本特征:
通过继承联系在一起的类构成一种层次关系。通常在层次关系的根部有一个基类,其他类则直接或间接地从基类继承而来,这些继承得到的类称为派生类。基类负责定义在层次关系中所有的类共同拥有的成员,而每个派生类定义各自特有的成员。
在C++语言中,基类将类型相关的函数与派生类不做改变直接继承的函数区分对待。对于某些函数,基类希望它的派生类各自定义适合自身的版本,那么基类就将这些函数声明成虚函数。
class A; //基类(父类)
{
public:
void Func1(void);
void Func2(void);
int i = 0;
};
class B:public A //子类(派生类),继承关系是public,还有两种protected、private继承关系
{
void func3(void);
void func4(void);
}
int main()
{
B.b;
b.i; //B继承A的数据类型i
b.func1(); //B继承A的函数成员func1
b.func2(); //B继承A的函数成员func2
b.func3();
return 0;
}
在c++语言中,基类以两种成员函数分为两类:一是基类希望其派生类进行覆盖的函数;另一种是基类希望派生类直接继承而不要改变的函数。对于前者,是通过在派生类中对基类的函数后面加一个关键字override,基类通过在其成员函数的声明语句之前加上关键字virtual,即为虚函数,当我们使用指针或者引用调用虚函数时,该调用将被动态绑定(下面会讲)。根据引用或指针所绑定的对象类型不同,该调用可能执行基类也可能执行某个派生类版本。
OOP的核心思想是多态性,其含义是“多种形式”,简单概括为“一个接口,多种方法”,只有当程序在运行时才决定调用的函数。C++多态性是通过虚函数来实现的,虚函数允许子类(派生类)重新定义成员函数,而子类重新定义基类的做法称为覆盖(override),或者称为重写。(这里我觉得要补充,重写的话可以有两种,直接重写成员函数和重写虚函数,只有重写了虚函数的才能算作是体现了C++多态性)而重载则是允许有多个同名的函数,而这些函数的参数列表不同,允许参数个数不同,参数类型不同,或者两者都不同。编译器会根据这些函数的不同列表,将同名的函数的名称做修饰,从而生成一些不同名称的预处理函数,来实现同名函数调用时的重载问题。但这并没有体现多态性。
多态与非多态的实质区别就是函数地址是早绑定还是晚绑定。如果函数的调用,在编译器编译期间就可以确定函数的调用地址,并生产代码,是静态的,就是说地址是早绑定的。而如果函数调用的地址不能在编译器期间确定,需要在运行时才确定,这就属于晚绑定。
封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用。也就是说,不论传递过来的究竟是那个类的对象,函数都能够通过同一个接口调用到适应各自对象的实现方法。
虚函数的调用:当某个虚函数通过指针或引用引用调用时,编译器产生的代码直到运行时才能确定应该调用那个版本的函数,被调用的函数是与绑定到指针或引用上的对象的动态类型相匹配的哪一个。
当我们在派生类中覆盖某个虚函数时,可以再一次使用virtual关键字指出函数性质。然而并非如此,因为一旦某个函数被声明成虚函数,则所有派生类中它都是虚函数。
纯虚函数是在声明虚函数时被“初始化”为0的函数。在虚函数的声明之后,分号之前加一个=0就可以将一个虚函数定义成一个纯虚函数,其中,基类内部只能出现声明,不能有定义,基类只提供接口,派生类可以实现不同定义。
含有(未经覆盖直接继承)纯虚函数的类是抽象基类,因为纯虚函数是不能被调用的,包含纯虚函数的类是不能无法建立对象的,它只负责定义接口,后续其他类可以覆盖该接口。
class Shape
{
virtual float area() const {return 0.0;}
virtual float volume() const {return 0.0;}
virtual void shapeName() cosnt = 0;
};
class Point:public Shape
{
public:
Point(float =0; float= 0);
void shapeName() const {cout<<"Point:";}
}
每个类分别控制自己的成员初始化过程,与之类似,每个类还分别控制着其他对于派生类来说是可访问的。继承的访问方式分为:公有继承、私有继承和保护继承。
#include
#include
using namespace::std;
class A
{
public:
string pub_mem;
protected:
int prot_mem;
private:
char priv_mem;
};
class B : public A //B继承A,继承关系是public
{
public:
string func1(){ return pub_mem; } //派生类可以访问基类的public成员
int func2() { return prot_mem; } //派生类可以访问基类的protected成员
//char func3(){ return priv_mem; } //派生类不可以访问基类的private成员
};
class C : private A //B继承C,继承关系是private
{
string func4() const{ return pub_mem; }
int func5() const{ return prot_mem; }
//char func6() const{ return priv_mem; }
};
class D : protected A //B继承C,继承关系是protected
{
string func7() const{ return pub_mem; }
int func8() const{ return prot_mem; }
//char func9() const{ return priv_mem; }
};
int main()
{
A a;
B b;
C c;
D d;
//基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,
//而基类的私有成员仍然是私有的,不能被这个派生类的子类所访问。
b.pub_mem;
//b.priv_mem; //错误
//b.prot_mem; //错误
//基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问.
//c.pub_mem; //错误
//c.priv_mem; //错误
//c.prot_mem; //错误
//基类的所有公有成员和保护成员都成为派生类的保护成员,
//并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。
//c.pub_mem; //错误
//c.priv_mem; //错误
//c.prot_mem; //错误
return 0;
}
继承的方式总结如下:
派生类到基类的转换
//派生类到基类的类型转化
A item; //基类对象
B bulk; //派生类对象
A *p = &item; //p指向了基类对象item
p = &bulk; //p指向了派生类的基类部分
A &r = bulk; //r绑定了派生类的基类部分
我需要知道一下几个名词:
举例:
#include
using namespace::std;
class base
{
public:
virtual void func()
{
cout << "The func from base." << endl;
}
};
class child : public base
{
public:
void func()
{
cout << "The func from child." << endl;
}
};
int main()
{
base *pb = new base;
child *pc = new child;
base p;
pb->func(); //调用base::func(),因为pb的静态类型和动态类型都是base;
pc->func(); //调用child::func(),因为pc的静态类型和动态类型都是child;
cout << endl;
pb = pc;
pb->func(); //调用base::func(),因为pb的静态类型是base,动态类型是child;
pc->func(); //调用child::func(),因为pc的静态类型和动态类型都是child;
cout << endl;
base p1;
child p2;
p1 = p2;
p1.func(); //调用base::func(),因为静态类型在编译时就确定下来了;
p2.func(); //调用child::func()
return 0;
}
结果:
http://www.cnblogs.com/iloverain/archive/2016/08/05/5726752.html
https://blog.csdn.net/hackbuteer1/article/details/7475622