如何为每个派生类存储一个可以从基类访问的幻数?

时间:2010-12-19 02:18:50

标签: c++ inheritance static constants

class User {
    public:
        int v() {
            return min_pass_len;
        }
        static const int min_pass_len = 10;
};
class AdminUser : public User {
    public:
        int w() {
            return min_pass_len;
    }

    static const int min_pass_len = 42;
};

然后

int main() {
    AdminUser a;
    std::cout << a.v()  << " why? " << a.w() <<  std::endl;
    return 0;
}

我可以以某种方式避免额外的方法调用吗?我也对其他解决方案,最佳实践感兴趣。谢谢!

4 个答案:

答案 0 :(得分:3)

只需使用返回不同数字的虚方法,跳过静态变量。

class User {
    public:
        virtual int v() {
            return 10;
        }
};

class AdminUser : public User {
    public:
        virtual int v() {
            return 42;
    }    
};

答案 1 :(得分:1)

您错过了virtual关键字。在C ++中,默认情况下,方法不是虚拟的,就像它们在某些其他编程语言中一样(例如,Java)。请尝试以下方法:

#include <iostream>

class User {
    static const int min_pass_len = 10;
public:
    virtual ~User() {}
    virtual int getPasswordLength() const {
        return min_pass_len;
    }
};

class AdminUser: public User {
    static const int min_pass_len = 42;
public:
    virtual ~AdminUser() {}
    virtual int getPasswordLength() const {
        return min_pass_len;
    }
};

int
main()
{
    AdminUser a;
    User u, *p = &a;
    std::cout
        << u.getPasswordLength() << "\n"
        << a.getPasswordLength() << "\n"
        << p->getPasswordLength() << "\n"
        << std::endl;
    return 0;
}

如果你想完全摆脱这个方法,那么要么使用"curiously reoccuring template pattern" mentioned by Sanjit的例子,要么外化常量而不是将它嵌入到类中。我在考虑类似于std::numeric_limits的实现方式:

template <typename T>
struct UserTraits {
    static const int minimum_password_length = 0;
};

template<> struct UserTraits<User> {
    static const int minimum_password_length = 10;
};
template<> struct UserTraits<AdminUser> {
    static const int minimum_password_length = 10;
};

int main() {
    std::cout
        << UserTraits<User>::minimum_password_length << "\n"
        << UserTraits<AdminUser>::minimum_password_length << "\n"
        << std::endl;
    return 0;
}

我通常更喜欢第一种方法,因为它有一个指向实例的指针。后一种方法几乎没有用,因为你不能使用它从实例中提取常量而不需要编写自由函数,即使你失去了动态类型的方面。

template <typename T>
int getPasswordLength(T*) {
    return UserTraits<T>::minimum_password_length;
}
template <typename T>
int getPasswordLength(T&) {
    return UserTraits<T>::minimum_password_length;
}

这种方法的问题在于,如果您在第一个代码段中使用getPasswordLength(p)调用p,则会得到错误的结果。

答案 2 :(得分:1)

最佳做法会建议使用virtual函数(这就是为什么它们被引入,以使旧代码能够调用新代码):

class base{
public:  virtual int get_magic(){return 10;};
};

class der1: public base{
public:  virtual int get_magic(){return 42;};
};

然而,在基类中定义的一个简单变量,但在每个派生的构造函数中重写会更快,并且会消除任何调用(因为它将被内联):

class base{
protected:  int magic; // note that it's not static!
public:
    base(){magic = 10;};
    int get_magic(){return magic;};
};

class der1: public base{
public:
    der1(){magic = 42;};
};

答案 3 :(得分:0)

如果你想为不同的派生类设置不同的常量,你应该像这样模板化基类:

template<class T>
class User 
{
    // Make the password len getter virtual.
    virtual GetPassLen() { return min_pass_len; }
    ...
    static const int min_pass_len = 10;
}

class AdminUser : public User<AdminUser>
{
}

// All admin users get this constant
AdminUser::min_pass_len = 42;

class GuestUser : public User<GuestUser>
{
}

// Guest user can have a different constant than Admin user.
Guestuser::min_pass_len = 0;
相关问题