C ++无法从父级访问子属性

时间:2016-05-21 07:48:48

标签: c++ inheritance

有人可以解释为什么Driver init()方法无法打印在子级中覆盖的name属性吗?

#include <iostream>
#include <string>

class Driver {
public:
    std::string name = "Unknown";

    void init() {
        std::cout << name << std::endl;
    }
};

// need public here to inherit init()
class SpecificDriver : public Driver {
public:
    std::string name = "Specific";

};

int main() {
    Driver d;
    SpecificDriver sd;

    // this gives Unknown Unknown =/
    d.init();
    sd.init();
}

这给出了:

Unknown
Unknown

应该是:

Unknown
Specific

Live Demo

3 个答案:

答案 0 :(得分:4)

你的表现并不像你认为的那样。您在驱动程序中声明变量“name”,在SpecificDriver中声明变量“name”。当您调用基类驱动程序中定义的init()时,该驱动程序只能访问其值为“unknown”的name字段。

相反,您应该使用构造函数初始化“name”变量。

像这样:

class Driver {
public:
    std::string name;

    Driver():name("Unknown"){} //default
    Driver(std::string value):name(value){}

    void init() {
        std::cout << name << std::endl;
    }
};

// need public here to inherit init()
class SpecificDriver : public Driver {
public:
    SpecificDriver():Driver("Specific"){}
};

int main() {
    Driver d;
    SpecificDriver sd;

    d.init();
    sd.init();
}

编辑:现场演示http://coliru.stacked-crooked.com/a/c453758867454348

答案 1 :(得分:2)

在C ++中,虚拟继承是选择加入而不是隐式的。

当你有这个代码时

class Driver {
public:
    std::string name = "Unknown";

    void init() {
        std::cout << name << std::endl;
    }
};

符号name将根据当时的范围静态解析。

如果稍后声明全局变量name,则它对此代码的含义没有影响。如果您稍后从此类Driver派生,init函数在继承该类时,则不会有不同的含义,如您的示例所示。

这&#34;静态&#34; dispatch是C ++中的默认行为,因为它是最简单和最快的行为。特别是,如果你以后使用模板和继承来做这件事很重要,否则很多代码会有很多额外的开销。

Alex Zywicki展示了一种可以达到你想要的方式。另一种方法是使用虚拟分派来获取字符串。像这样:

class Driver {
public:
    virtual std::string name() const {
        return "Unknown";
    }

    void init() {
        std::cout << name() << std::endl;
    }
};

class SpecificDriver : public Driver {
    virtual std::string name() const override {
        return "Specific";
    }
};

答案 2 :(得分:0)

可以通过CRTP访问子类的类成员。

#include <iostream>

template <typename Derived>
class Driver {
public:
    void init() {
        std::cout << static_cast<Derived*>(this)->name << std::endl;
        std::cout << Derived::value << std::endl;
    }
};

class SpecificDriver : public Driver<SpecificDriver> {
public:
    std::string name = "Specific";
    static constexpr char* value = "Another specific string";
};

int main() {
    SpecificDriver g;
    g.init();
}

如果您需要一个公共基类来存储这些内容,或者与正常的多态行为相结合,您可以使模板类Driver继承自公共基类。