C++ 在初始化时使用基类的常量

C++ 在初始化时使用基类的常量,c++,inheritance,constructor,constants,C++,Inheritance,Constructor,Constants,让我们假设有一个具有常量值的基类,一个从基类派生的中间子类,以及一个从中间类派生的最终派生类 如果我们想在派生类的初始值设定项列表中使用常量,我们将如何做到这一点 下面是一个示例代码: #include <iostream> class Base{ protected: const std::size_t c; Base() : c(64){} }; class Intermediate : public Base{ public

让我们假设有一个具有常量值的基类,一个从基类派生的中间子类,以及一个从中间类派生的最终派生类

如果我们想在派生类的初始值设定项列表中使用常量,我们将如何做到这一点

下面是一个示例代码:

#include <iostream>

class Base{
    protected:
        const std::size_t c;

        Base() : c(64){}
};

class Intermediate : public Base{
    public:
        Intermediate(int val){
            std::cout << "In Intermediate c is " << c << std::endl; // In Intermediate c is 64
            std::cout << "However, val = " << val << std::endl;     // However, val = 10
        }
};

class Derived : public Intermediate{
    public:
        Derived(int val) : Intermediate(this->c+val){
            std::cout << "In Derived c is " << c << std::endl;      // In Derived c is 64
        }
};

int main(){
    Derived instance(10);

    return 0;
}
#包括
阶级基础{
受保护的:
常量标准::大小\u t c;
Base():c(64){}
};
中级班:公共基地{
公众:
中间值(int-val){

std::cout在处理构造函数之前,您已经使用了此值。 您使用了
c
符号作为构造函数的参数,结果造成了一个鸡蛋问题

在编译器中启用
-Wall
开关以捕获此类问题。
编译器警告您正在执行可疑操作:

prog.cc:在构造函数“派生::派生(int)”中:
程序cc:20:47:警告:'*.派生::

类基{
受保护的:
静态常数std::size\t cDefaultValue=64;
常量标准::大小\u t c;
Base():c(cDefaultValue){}
};
中级班:公共基地{
公众:
中间值(int-val){

std::cout您只需要中间层中接受基本访问者的受保护的ctor。然后您可以提供中间层可以使用的任何类型的访问者(=计算),从而具有多个子体。您甚至可以通过模板将其设为静态访问者

class Intermediate {
public:
    Intermediate(int val) { ... }

protected:
    template<typename V>
    Intermediate(V vis)
        : Intermediate(vis(*static_cast<const Base*>(this))) {}
};

class Derived {
public:
    Derived(int val)
        : Intermediate( [&](const Base& base) { return base.c + val; }) { ... }
};
中级{
公众:
中间值(int-val){…}
受保护的:
模板
中间体(V-vis)
:中间(vis(*static_cast(this))){
};
类派生{
公众:
派生(int-val)
:中间([&](const Base&Base){return Base.c+val;}){…}
};

因为您在处理构造函数之前使用了这个值。您使用了
c
符号作为构造函数的参数,结果造成了一个鸡蛋问题。@MarekR这不是鸡蛋:在base上执行的计算是事先知道的,因此可以传递给Intermediate。我知道这是错误的(我在问题中说过)。除了我提出的解决方案之外,我还想知道一个解决方案。有趣的是,g++(gcc版本7.2.1 20170915(Red Hat 7.2.1-2)(gcc))即使在这里使用-Wall也不抱怨。有趣的是,它应该对此提出警告。关于我的用例,基类有一个属于每个子类的常量属性。我可以将其设置为静态,因为这似乎是最合理的方法(尽管我不明白为什么要创建第二个常量,如果一个常量就足够了),但你会说使用另一种方法更可取吗?(我在想作文是否是一种合适的方法)如果我只对const值感兴趣,而其他所有问题都通过继承得到了妥善解决,这难道不是一种过分的杀伤力吗?可能是过度杀伤力,开销一点也没有。如果您的团队不习惯函数式编程,并且您有其他可能的设计(例如静态、基于枚举的ctor等),您可能希望跳过这一步。(2在你的列表中我会跳过,3我不知道它们之间有什么联系)。然而,这是一般性的,可以在任何地方使用。好吧,这对我的需求来说肯定是一种过分的做法,但它与我提出的方法不同,所以,在这里,有一个cookie。
class Base{
    protected:
        static const std::size_t cDefaultValue = 64;
        const std::size_t c;

        Base() : c(cDefaultValue){}
};

class Intermediate : public Base{
    public:
        Intermediate(int val){
            std::cout << "In Intermediate c is " << c << std::endl; // In Intermediate c is 64
            std::cout << "However, val = " << val << std::endl;     // However, val = 10
        }
};

class Derived : public Intermediate{
    public:
        Derived(int val) : Intermediate(cDefaultValue + val){
            std::cout << "In Derived c is " << c << std::endl;      // In Derived c is 64
        }
};
class Intermediate {
public:
    Intermediate(int val) { ... }

protected:
    template<typename V>
    Intermediate(V vis)
        : Intermediate(vis(*static_cast<const Base*>(this))) {}
};

class Derived {
public:
    Derived(int val)
        : Intermediate( [&](const Base& base) { return base.c + val; }) { ... }
};