2016-01-25 126 views
0

要定义第二个const版本的函数,是否可以安全地执行此操作?它看起来像会有无限递归,因为我想返回const,但我打算调用的另一个函数是非const。可能会导致无限循环?

它适用于g ++,但我担心这是不安全的。

#include <iostream> 

using namespace std; 

class test { 
public: 
    int* doSomething(int a) { 
     int* someInt = new int(a); 

     return someInt; 
    } 

    const int* doSomething(int a) const { 
     return doSomething(a); 
    } 
}; 

int main() { 
    test a; 

    cout << *a.doSomething(12345) << endl; 

    return 1; 
} 
+3

此代码调用doSomething'的'非const版本。尝试调用const版本并观看它爆炸。 –

+0

为什么不在分配它时初始化'someInt':'int * someInt = new int(a);' – erip

+0

我一直认为C++不允许超载仅返回类型不同的函数.... – Anedar

回答

2

不太:作为@Pete贝克尔在评论中指出的,如果你曾经被称为const版本递归:

class test { 
public: 
    int* doSomething(int a) { 
     int* someInt = new int; 
     *someInt = a; 
     return someInt; 
    } 

    const int* doSomething(int a) const { 
     return doSomething(a); 
    } 
}; 

int main() { 
    const test a; 
    // You're not in for a good time: 
    a.doSomething(12345); 
    return 1; 
} 

在提供const和非const版本的函数是需要重复的代码,最好实施const版本,然后让非const版本以特定方式调用它。

从斯科特迈尔斯Effective C++ - Third Edition

const和非const成员函数具有基本上相同的实施方式中,代码重复可以通过使非const版本调用const版本

避免斯科特·迈尔斯继续提供一个安全的方法来做到这一点:

const int* doSomething(int a) const 
{ 
    int* someInt = new int; 
    *someInt = a; 
    return someInt; 
} 

int* doSomething(int a) 
{ 
    return const_cast<int*>(static_cast<const Test&>(*this).doSomething()); 
} 

在非const版本,有两种类型转换:在static_cast基本上变成thisconst this,其中const_cast擅自抛弃的const -ness的回报。这是安全的,因为要拨打非const版本,您必须拥有非const this

但是,如果你只是提供一个成员访问,它的简单和易于阅读,只是有以下几点:

class TestAccess; 
class Test 
{ 
    TestAccess& t; 
public: 
    const TestAccess& getA() const { return t; } 
    TestAcess& getA() { return t; } 
}; 
+0

Scott Myers的解决方案非常完美。我试图想,如果有一种方法可以从'const'的某种方式调用non-'const'版本,我不认为你可以。谢谢你清楚地解释这一点。部分问题是我对const方法的工作原理的误解:http://stackoverflow.com/questions/34983475/why-is-stdbasic-stringoperator-a-const-method-if-its-also-a-non- const-met?answertab = active#tab-top – Zhro

+0

任何需要'const'版本调用非''const'版本的警告?似乎工作正常。 – Zhro

+0

是的:一个'const'成员函数承诺永远不会改变一个对象的状态,但是你基本上会调用一个非''constst'函数来改变对象的状态。非''constst'版本调用'const'版本更安全,因为非''constst''函数可以为对象做任何事情。 – Tas

0

在这种情况下,编译器总是会选择函数的非const版本,甚至不会调用const函数。 否则编译器将不会编译,您正在制动constenss。 比如我修改迅速代码:

#include <iostream> 

using namespace std; 

class test { 
public: 
    int* doSomething(int a) { 
     int* someInt = new int; 

     *someInt = a; 
     return someInt; 
    } 
    int ax = 10; 
    void somethingElse(int i) 
    { 
     ax = i; 
    } 
    const int* doSomething(int a) const { 
     somethingElse(a); 
     return 0; 
    } 
}; 

int main() { 
    test a; 

    cout << *a.doSomething(12345) << endl; 

    return 1; 
} 

这个例子并不能编译,因为你调用一个const范围内const函数。编译器不会让你这样做。

现在,我知道是一个测试,但通过这种方式,你永远不会退出递归,它将永远循环,并且在每次调用时都会通过在堆上分配来泄漏内存,这两件事在一起可能会导致发生灾难。

+0

我知道它正在泄漏内存。这只是一个例子。 – Zhro

+0

出于对编码风格的好奇,是'somethingElse()'缩进8个空格的原因,还是这是一个错误? – Zhro

+0

你可以只返回int本身,即使是测试也不明白为什么你需要一个泄漏指针。无论如何不是重点。 关于括号,是的错,我赶紧编码,并必须在复制粘贴 干杯 被搞砸 M. –