在继承class中重新定义一个常量成员变量

Redefine a constant member variable in inherited class

假设我希望在父 class 中定义一个成员变量,并在继承的 class 中设置它的值。也许这些标识了 class 中可用的功能或子 class 的性质。例如:

class A
{
public:
    inline int getX() { return x; }
protected:
    const int x = 0;
};

class B : public A
{
protected:
    const int x = 10;
};

class C : public A
{
protected:
    const int x = 50;
};

不言而喻,范围问题会阻止上述功能正常工作。但是,有没有办法让这项工作按预期进行?

因为变量是为了识别继承的classes的性质,所以我更喜欢它是const——如果它不是const并且只是在构造函数中重新定义就不会出现这个问题,所以据我所知。

在摆弄编译器以确保我的示例代码有意义时,我实际上遇到了一个事实,即我尝试定义常量的方式是特定于 C++11 的。这让我研究了以前的做法,我发现 this question,这间接地阐明了这个问题。

以这种方式定义变量应该通过让基 class 在其构造函数中采用以下形式的参数来完成:

class A
{
public:
    A( const int& type ) : x(type) {}
    inline int getX() { return x; }
protected:
    const int x;
};

class B : public A
{
public:
    B() : A(10) {}
};

class C : public A
{
public:
    C() : A(50) {}
};

这将按预期工作并允许常量 x 被继承的 classes 重新定义。

为了证明我在评论中提出的观点,这里有一个我认为你正在尝试做的事情的例子(从评论中推导出来)。

我在同一个程序中提供了鸭子类型和多态解决方案,每个解决方案都有一个定时 运行。

我使用了 1000 万个样本来消除内存缓存噪声。

您会注意到多态解决方案的 运行 时间明显少于鸭子类型解决方案的时间。

#ifdef _WIN32
#include <Windows.h>

double get_cpu_time(){
    FILETIME a,b,c,d;
    if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){
        //  Returns total user time.
        //  Can be tweaked to include kernel times as well.
        return
        (double)(d.dwLowDateTime |
                 ((unsigned long long)d.dwHighDateTime << 32)) * 0.0000001;
    }else{
        //  Handle error
        return 0;
    }
}
#else
#include <sys/time.h>

inline double get_cpu_time() noexcept {
    return (double)clock() / CLOCKS_PER_SEC;
}

#endif


#include <iostream>
#include <vector>
#include <memory>

struct A
{
    A(bool copy_) : copy{copy_} {}

    virtual ~A() = default;
    const bool copy = false;
};

struct RealA : public A
{
    RealA() : A { false } {}
};

struct CopyA : public A
{
    CopyA() : A { true } {}
};

// A Thing holder will hold any object which has an interface supports do_something_to(T& thing)

struct AHolder {

    template<class Thing>
    AHolder(std::unique_ptr<Thing> ptr)
    : _ptr { std::move(ptr) }
    {

    }

    template<class Thing, class...Args>
    static AHolder construct(Args&&...args)
    {
        return AHolder { std::make_unique<model<Thing>>(std::forward<Args>(args)...) };
    }

    void do_something() const {
        _ptr->do_something();
    }
private:
    struct concept {
        virtual ~concept() = default;

        virtual void do_something() = 0;
    };
    template<class Thing> struct model : concept {
        template<class...Args>
        model(Args&&...args) : _thing { std::forward<Args>(args)... } {}
    private:
        void do_something() override {
            do_something_to(_thing);
        }
        Thing _thing;
    };

    std::unique_ptr<concept> _ptr;
};


using namespace std;

size_t copies_processed = 0;
size_t reals_processed = 0;

void do_something_to(const CopyA&)
{
    // simulate work
    ++copies_processed;
}

void do_something_to(const RealA&)
{
    // simulate work
    ++reals_processed;
}


int main(int argc, char **argv) {

    std::vector<std::unique_ptr<A>> duck_typing;
    std::vector<AHolder> polymorphic;

    constexpr size_t samples = 10000000;

    for (size_t i = 0 ; i < samples ; ++i) {
        if (i % 2) {
            duck_typing.push_back(make_unique<RealA>());
            polymorphic.emplace_back(AHolder::construct<RealA>());
        }
        else {
            duck_typing.push_back(make_unique<CopyA>());
            polymorphic.emplace_back(AHolder::construct<CopyA>());
        }
    }

    auto duck_start = get_cpu_time();
    // nasty duck-typing solution
    for (const auto& ptr : duck_typing) {
        if (ptr->copy) {
            do_something_to(*(static_cast<CopyA*>(ptr.get())));
        }
        else {
            do_something_to(*(static_cast<RealA*>(ptr.get())));
        }
    }
    auto duck_stop = get_cpu_time();

    auto poly_start = get_cpu_time();
    for (const auto& a_like : polymorphic) {
        a_like.do_something();
    }
    auto poly_stop = get_cpu_time();

    cout << "duck typing : " << duck_stop - duck_start << endl;
    cout << "polymorphic : " << poly_stop - poly_start << endl;

    cout << "copies processed : " << copies_processed << endl;
    cout << "reals processed : " << reals_processed << endl;

    return 0;
}

示例输出:

duck typing : 0.162985
polymorphic : 0.137561
copies processed : 10000000
reals processed : 10000000