c++接口类的实现

c++不像java一样有纯接口类的的语法,但我们可以通过一些手段实现相同的功能。

一:

考虑这样的代码:

class A
{
protected:
virtual ~A()
{
cout << __FUNCTION__ << endl;
}
};

class B : public A
{
public:
virtual ~B()
{
cout << __FUNCTION__ << endl;
}
};

int _tmain(int argc, _TCHAR* argv[])
{
A* p1 = new A; //[1]有问题
delete p1;

B* p2 = new B;
delete p2; //[2]没问题的

A* p3 = new B;
delete p3; //[3] 有问题

return 0;
}

通过在类中,将类的构造函数或者析构函数申明成protected ,可以有效防止类被实例话,要说实用的话,构造函数是protected更有用,肯定能保证类不会被实例化,而如果析构函数是protected的话,构造函数不是protected的话,还可能存在编译通过的漏洞,如下:

A:

class A
{
protected:
A()
{
cout << __FUNCTION__ << endl;
}
};

int _tmain(int argc, _TCHAR* argv[])
{

A* p1 = new A; //编译不通过,无法访问protected构造函数
delete p1;

return 0;
}

B:

class A
{
protected:
~A()
{
cout << __FUNCTION__ << endl;
}
};

int _tmain(int argc, _TCHAR* argv[])
{
A* p1 = new A; //编译通过,此时因为仅仅是用到了A的构造函数,还不需要它的析构函数

return 0;
}

C:

class A
{
protected:
~A()
{
cout << __FUNCTION__ << endl;
}
};

int _tmain(int argc, _TCHAR* argv[])
{
A* p1 = new A;
delete p1; //编译失败,因为编译器发现A的析构函数是protected

return 0;
}


所以,一种可行的办法貌似是这样的:

class A
{
protected:
virtual ~A()
{
cout << __FUNCTION__ << endl;
}
};

class B : public A
{

};

int _tmain(int argc, _TCHAR* argv[])
{
B* p =new B; //这种情况下确实是可行的
delete p;

return 0;
}

由于B public继承自A,所以其可以完全访问A的构造或析构函数,但是:

int _tmain(int argc, _TCHAR* argv[])
{
A* p =new B;
delete p; //由于p变成指向A的指针,字面上编译器需要知道A的析构函数,然后A的析构函数又是protected

return 0;
}

即便像这样B显示重载了A的析构函数:

class A
{
protected:
virtual ~A()
{
cout << __FUNCTION__ << endl;
}
};

class B : public A
{
public:
virtual ~B()
{
cout << __FUNCTION__ << endl;
}
};

int _tmain(int argc, _TCHAR* argv[])
{
A* p =new B;
delete p; //也还是不行,因为重载是运行时的事情,在编译时编译器就认定了A的析构函数,结果无法获取

return 0
}

小结:

貌似用protected这样的方法并不是很恰当,虽然在遵守一定规则的情况下确实有他的实用价值,但并不是很通用。

二:

其实上面protected的思路是对的,无非是让父类无法实例化,那么为了让父类无法实例化,其实还有一个方法,使用纯虚函数。

class A
{
public: //这里就不用protected了
virtual ~A() = 0;
};

class B : public A
{
};

int _tmain(int argc, _TCHAR* argv[])
{
B* p =new B;
delete p;

return 0;
}

这样写貌似不错,以往大家都把类中的一般成员函数写成纯虚的,这次将析构函数写成纯虚的,更加增加通用性,编译也通过了,但就是在链接的时候出问题,报错说找不到A的析构函数的实现,很显然吗,因为A的析构是纯虚的吗。

class A
{
public: //这里就不用protected了
virtual ~A() = 0 //它虽然是个纯虚函数,但是默认实现,可以有
{ //这个语法很好很强大,经过小强的指点终于高清了他的用法(完全是为了实现其接口类而弄的语法吧)
cout << __FUNCTION__ << endl;
}
};

class B : public A
{
};

int _tmain(int argc, _TCHAR* argv[])
{
B* p =new B;
delete p;

A* p2 =new B;
delete p2; //不用担心编译器报错了,因为此时A的析构函数是public

return 0;
}

如此终于大功告成了,注意,不能将构造函数替代上面的析构函数的用法,因为构造函数是不允许作为虚函数的。

补充:以上那个语法就真的只是为了这种情况而存在的,因为一般我们在虚类中申明的接口:
virtual foo() = 0;

virtual foo() = 0 {}

这两种写法是完全没有区别的,纯虚函数的默认实现,仅仅在它是析构函数中才有意义!!!

所以可以说,老外是完全为了这一个目的而发明了这种语法...

最终的接口类

class Interface
{
public:
virtual ~Interface() = 0 {}
};

应该挺完美的了吧,hiahia

你可能感兴趣的:(C++,c,C#)