C++继承和受保护基类成员的访问:用Java风格做这件事是个坏主意吗



不幸的是,我主要在Java环境中学习类设计和设计模式;因此,我有时很难将熟悉的模式翻译成C++。

假设我们想要一个基类,它的功能由一个子类扩展。在Java中,我们会做这样的事情:

public class BaseClass<T> {
     //T is used here
     protected int foo = 0;         
}
public class DerivedClass<T> extends BaseClass<T> {
    public void incr_foo() {
         ++foo;
    }
}

我直接翻译成C++:

template<class T>
class BaseClass {
protected:
    size_t foo = 0;
     //T is used here
};
template<class T>
class DerivedClass : public BaseClass<T> {
public:
     void incr_foo() {
          ++(this->foo);
     }
};

由于"protected"diver的C++语义来自Java语义,我们需要使用类似"this->foo"的东西来访问基类的受保护成员。

编辑:如果我们只使用"++foo",编译器会给出错误:"使用未声明的标识符foo"。

编辑结束

如果您需要访问基类的几个成员,这可能会有点乏味,阅读起来也不太好。

这是一个好的设计设计吗?如果没有,还有什么更好的方法可以实现这一点?

这与受保护的成员无关;公共成员也会出现完全相同的错误。

真正的原因是调用了模板。更具体地说,您的类模板有一个依赖于模板参数的基类。这意味着,在解析模板时,编译器将无法(能够(查看该基类,以找到使用不合格的继承成员。这是有道理的:当解析模板时,模板参数值还不知道,因此编译器不知道基类会有什么成员(记住存在部分和全部专业化!(。

为了克服这一点,您必须以某种方式告诉编译器名称foo取决于模板参数(它是一个依赖于的名称(。一旦这样做,编译器在解析模板时就不会试图解决它;它将推迟解析,直到模板被实例化。此时,模板参数是已知的,因此可以检查基类。

您有三种方法可以将成员名称标记为从属名称:

  1. 通过this引用名称,就像您正在做的那样:this->foo

  2. 通过基类鉴定参考名称:BaseClass<T>::foo

  3. 将名称带入派生类的范围:

    template<class T>
    class DerivedClass : public BaseClass<T> {
    protected:
         using BaseClass<T>::foo;  // from this point on, `foo` is a dependent name
    public:
         void incr_foo() {
              ++foo;  // works fine now
         }
    };
    

BaseClass<T>依赖类型-它取决于用于实例化DerivedClass的模板参数。在DerivedClass实例化之前,编译器不知道类型是什么:它可能是泛型模板的实例化,也可能是具有不同成员的显式专业化。

因此,在DerivedClass的定义中,无法知道哪些名称引用基类的成员。您必须使用this->BaseClass::指定它们是。

在具有非依赖基类的类中,您可以使用任何可访问的基类成员,就像它们是直接成员一样,就像在Java中一样。

相关内容

最新更新