首先定义一些简单的辅助说明类 :
class A
{
void func1();
}
class B public:A
{
void func1();
}
类A一般是做为基类,类B则继承了类A。
A a = new B();
a.func1();
这样的结果是调用了A的func1方法。
B b = new B();则是显然是调用B的func1方法。
因为像这样定义一个对象A a, 不管我们构造滴是一个什么样的对象,在编译期间,编译器只知道我们是个A类型,只会按照A类型生成func1方法,在运行时,也是调用A类的func1方法。
假如我们有需要有更多的类像类B一样,继承类A,而且都有不同func1方法实现。我们可以在基类A的func1方法前面加个virtual关键字,表示它是虚函数,A类就是这样
class A
{
virtual void func1();
}
B类的写法不变,当我们在使用
A a = new B();
a->func1();则会调用子类B的func1方法。
虚函数是c++中继承和多态实习的实现。(而java和oc中默认重写父类的方法就是可以实现多态)
关于纯虚函数
纯虚函数写法 virtual void func2() = 0;纯虚函数是虚函数的一种特殊化。
只要是类中包含了纯虚函数的类,都是不能实例化的抽象类。
class A
{
virtual void func2() = 0;
}
而我再定义A a的时候再编译的阶段就会报错(A中包含了纯虚函数,是抽象类,不能实例化)。
其他方面纯虚函数和虚函数意义完全一样,引入纯虚函数纯粹是为了编码的规范和效率。使得一些问题在编译期间就能察觉。
关于指针:
由于自己对C++特别是其中的指针,完全不太熟 ,只是写写关于自己遇到的问题。
定义一个类C
class C
{
int a;
}
定义以下几个函数:
func1(C* c)
{
c->a = 1;
}
func2(C& c)
{
c.a = 2;
}
func3(C c)
{
c.a = 3;
}
定义一个C c = new C();
c是一个C类的实例对象。
假如我们调用了func3(c),很显然a的内容不会改变。因为我们调用的时候函数的形参会生成一个c对象的临时拷贝。我们在func3函数里面改变的是那个临时拷贝,所有不能改变c对象的值。
假如我们调用了func2(c),我们传进去的是c的地址,改变的当然是c本身了,所以c的值肯定会改变。
而当我们调用了func1(&c),传进去的是c对象的地址 而函数形参是C* (C类型的指针)指向的是c对象的地址,所以也会改变c的值。
定义一个C* c = new C();
c是指向C类型实例的指针
当我们调用func1(c),传入的是c的指针,而函数形参也是一个C的指针,我的相当于做了这么一个操作C* c1 = c;将c1和c都指向了同一个内存对象,改变了c1 c也会跟着改变。
func2(*c)还是一样传入的时候会生成一个c的拷贝,所以还是不能改变c的内容。
func3(*c)跟上面道理一样,传入时候不会生成拷贝,所以能改变。
假如我们修改下func1函数的功能:
func1(C* c)
{
c = new C();
}
再按照如下的调用C* c = NULL; func1(c);这样能不能得到一个c对象呢。
显然是不能的,因为我们传入的是C类型的一个指针,当函数调用的时候C c1 = c;我们做的是将c1指向了c的指向地址,即NULL。当我们进行c1 = new C(),操作的时候即又将c1 指向了另外一个地址,即我们新构造的C对象地址,而我们至始至终都木有改变c的指向。 所以 c最终还是指向空。
解决这个问题又2中办法,第一种
func1(C *&);当我们在调用func1(c)的时候,传入的是指针自己的地址(而不是指针指向内容的地址),最终我们在func1函数中使用的指针还是原来的c指针,所以我们会得到正确的结果。
第二张
C& func1()
{
return C();
}
我们调用的时候C* c = func1();这样得到的结果也是正确的。