c++接口类的实现

来源:互联网 发布:你最努力的时候知乎 编辑:程序博客网 时间:2024/04/29 19:32

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

原创粉丝点击