【问题标题】:How to force a call to a const qualified function overload?如何强制调用 const 限定函数重载?
【发布时间】:2014-12-05 11:59:23
【问题描述】:

我试图在类中调用const 函数,但存在同名的非const 函数。

注意:我不能只更改名称。

class MyQuestion
{
 void fun()
 {
   cout<<"a"; 
 }

 void fun()const
 { 
   cout<<"b"; 
 }

 void call()
 {
   fun();//<how to call fun() const?
 }
};

【问题讨论】:

  • 它会根据*this指针的常量自动调用一个或另一个
  • 一个不太重复的问题的相关答案:stackoverflow.com/a/5326238/10077
  • 您需要调用函数的 const 版本似乎是错误的。这意味着虽然您的 const 和非 const 成员函数恰好具有相同的名称,但它们实际上做的是根本不同的事情。

标签: c++ constants overloading


【解决方案1】:

选项#1:

通过指向const 限定类型的指针调用该函数:

void call()
{
    static_cast<const MyQuestion*>(this)->fun();
    //          ~~~~^
}

:

void call()
{
    const auto* that = this;
    //~~^
    that->fun();
}

:

void call()
{
    std::as_const(*this).fun();
    //   ~~~~~~~^
}

选项#2:

使调用函数成为const-qualified:

void call() const
//          ~~~~^
{
    fun();
}

DEMO

【讨论】:

  • 我不太喜欢静态转换的冗长(明确提及类名)。您可以通过使用类型为 const auto* 的局部变量来避免这种情况。
  • 为什么使用 static_cast 而不是 const_cast?
  • @Thebluefish const_cast 通常表示抛弃 constness (我在这里做相反的事情),我不喜欢将它用于常规隐式转换,@ 987654332@ 无条件进行演员表
  • 我会在那里使用implicit_cast 而不是static_cast(或者使用@leemes 建议的本地)。即使我必须为自己编写它,或者从 boost 中导入它......
  • 比起使用这种情况,我更喜欢在内部使用 const 引用。 MyQuestion const&amp; self = *this; self.fun()
【解决方案2】:

你必须在 const 指针上调用函数。为此,我建议创建一个本地指针变量:

const auto *c = this;
c->fun();   // calls fun() const

fun();      // calls fun()

Live Demo


如果你经常需要,和/或如果你不想使用局部变量,你也可以引入一个返回 const this 指针的私有辅助函数:

const MyQuestion *const_this() const {
    return this;
}

然后像这样调用fun

const_this()->fun();   // calls fun() const

fun();                 // calls fun()

Live Demo


另一种选择是编写一个 make_const 函数,该函数执行对 const 指针的强制转换,而无需提及类名(它基本上是一个 static_cast 到推导类型的 const 指针):

template <typename T>
const T* make_const(T *ptr) {
    return ptr;
}

然后像这样调用fun

make_const(this)->fun();    // calls fun() const

fun();                      // calls fun()

Live Demo


为了论证(我不推荐以下),结合上面的建议,你还可以引入一个全局宏,扩展为make_const(this)

#define  const_this  make_const(this)

然后像这样调用fun

const_this->fun();   // calls fun() const

fun();               // calls fun()

Live Demo

【讨论】:

  • lambda 需要 C++14 或显式返回类型。 C++11 只能为只包含一个 return 语句的 lambda 推导出它。
  • @Angew 哦,不知道,因为 g++ 允许其他语句,我总是以这种方式使用 lambdas ......但很高兴知道,谢谢 :) -- 更新宏以扩展为而是调用函数。
  • @angew 在每个主要编译器中,“只有一行带有返回语句”的限制几乎持续了零时间。取消限制的 C++14 即将推出,就这么简单......
  • 我在我的代码库中调用 make_const as_const。并添加T&amp;T const&amp; 重载。
  • @Yakk 似乎在 C++17 中,std:: 中有 as_const() 函数:en.cppreference.com/w/cpp/utility/as_const 所以不必在不断增长的全球列表中添加另一个函数每个项目的实用功能。
【解决方案3】:

我想为已经发布的优秀解决方案添加另一个可能的解决方案。

您可以使用具有预期签名的函数指针帮助编译器选择正确重载:

// Pointer to the version of fun with const
void (MyQuestion::*f)()const = &MyQuestion::fun;
(this->*f)(); // This would call the const fun

查看演示 here,或下面的完整代码:

struct MyQuestion
{
    void fun()
    {
        std::cout<<"a"; 
    }

    void fun()const
    { 
        std::cout<<"b"; 
    }

    void call()
    {
        void (MyQuestion::*f)()const = &MyQuestion::fun;
        (this->*f)();
    }
};

为什么会这样?

好吧,f 指针的类型是void (MyQuestion::*)()const,它与MyQuestion::foo()const 相同,但与MyQuestion::foo() 不同,所以当您获取函数&amp;MyQuestion::fun 的地址时,指针@987654329 @ 只能指向 const 版本。

【讨论】:

    【解决方案4】:

    如何重载 call() 本身。以下实施完成了这项工作。我猜这是你想要实现的。

    #include <iostream>
    using namespace std;
    
    class A
    {
    public:
        void fun() { cout << "non" << endl; }
        void fun() const { cout << "const" << endl; }
    
        void call() { fun(); }
        void call() const { fun(); }
    };
    
    int main()
    {
        A a;
        a.call();
    
        const A b;
        b.call();
        return 0;
    }
    

    【讨论】:

    • 这可能行不通——call() 可能有很好的理由成为 const!
    • 只有当创建的对象是一个肯定会调用 const fun() 的 const 时才会调用 const call()
    • 你怎么知道call()fun()是同一个类的成员?我们可能会遇到这样一种情况:A::call() 需要是非常量的,因为它改变了它正在处理的 A 对象,但需要从使用 B::fun() const 的 A 对象引用的 B 中获取一些东西,其中非常量 B::fun()对 B 对象做了一些不需要的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多