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

发布于 2024-10-07 23:50:50 字数 518 浏览 4 评论 0原文

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;
}

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

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;
};

Then

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

Can I somehow avoid the extra method call? I'm also interested in other solutions, best practices. Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

哥,最终变帅啦 2024-10-14 23:50:50

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

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

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

Just use a virtual method that returns a different number, skip the static var.

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

class AdminUser : public User {
    public:
        virtual int v() {
            return 42;
    }    
};
掩于岁月 2024-10-14 23:50:50

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

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;

If you want to have a different constant for different derived classes, you should templatize the base class like so:

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;
躲猫猫 2024-10-14 23:50:50

您缺少 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;
}

如果您想完全摆脱该方法,请使用 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;
}

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

You are missing the virtual keyword. In C++ methods are not virtual by default like they are in some other programming languages (e.g., Java). Try the following instead:

#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;
}

If you want to get rid of the method altogether, then either use the example of the "curiously reoccuring template pattern" mentioned by Sanjit or externalize the constant instead embedding it within the class. I was thinking of something similar to how std::numeric_limits is implemented:

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;
}

I usually prefer the first approach since it works when you have a pointer to an instance. The latter method isn't nearly as useful since you cannot use it to extract the constant from an instance without resorting to writing a free function and even then you loose the dynamic typed aspect.

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

The problem with this approach is that you would get the wrong result if you called getPasswordLength(p) using p in the first snippet.

心安伴我暖 2024-10-14 23:50:50

最佳实践建议使用virtual函数(这就是引入它们的原因,以使旧代码能够调用新代码):

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

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

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

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;};
};

Best practices would recommend use of virtual function (this is why they were introduced, to make old code able to call new code):

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

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

Howerer, a simple variable defined in the base class, but rewritten in each derived constructor would be faster and would eliminate any call (since it would be inlined):

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;};
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文