为什么const正确性规则不适用于内置库?

时间:2019-03-09 17:12:10

标签: c++ math.h const-correctness

关于const方法有一条规则。如果该方法是const,并且我们试图在同一方法中使用另一个函数,那么它也应该是const。否则,我们将出现编译错误。我试图在math.h库中找到abs()函数的声明,这是我发现的内容:Declarations of abs() 这意味着abs()函数不是const,但是当我在const方法中使用它时,我没有编译错误。有人可以解释为什么吗?

class D:public B,C
{
public:
    D()
    {
        cout<<"This is constuctor D"<<endl;
    }

    int fun3() const;

    ~D()
    {
         cout<< "Destructor D"<<endl;
    }
};

int D::fun3() const
{
    int x=-3;

    return abs(x);
}

4 个答案:

答案 0 :(得分:3)

这里对const成员函数的约束存在误解。

const成员函数可以调用所需的任何函数,只要它不更改对象的状态即可。因此fun3()的编译效果很好,因为它不会更改任何成员变量,并且不会为同一对象调用任何非常量成员函数。

重要说明: public B,C可能与您的想法无关:这意味着D公开地继承自B,而私有地继承自C。从C公开继承,您必须声明public B, public C

答案 1 :(得分:3)

首先,请取消了解您认为的知识。让我们看看成为const成员意味着什么。

class D {
public:
    int fun2();
    int fun3() const;
};

这说明了什么?有一个名为D的类。有两个成员函数fun2fun3,每个成员函数都带有一个隐藏的this参数,而没有其他参数。

等等!隐藏参数?嗯,是。您可以在函数内使用this;它的价值必须来自某个地方。所有非静态成员函数均具有此隐藏参数。但是,并非所有非静态成员函数都具有相同类型的隐藏参数。如果要显示隐藏参数,则声明将如下所示:

int D::fun2(D * this);
int D::fun3(const D * this);

注意const在此伪声明中如何存在?这就是声明const成员函数的效果:this指向const对象,而不是非const对象。

现在回到问题。 fun3可以呼叫fun2吗?好吧,fun3会将其this指针(指向常量对象的指针)传递给fun2,后者需要一个指向对象的指针。那将意味着失去稳定性,所以这是不允许的。

fun3可以打电话给abs吗?好吧,fun3会将一个整数传递给abs。没问题问题是失去了this的稳定性。只要避免这种情况,就可以了。

答案 2 :(得分:0)

const应用于方法仅表示this指针,即指向该方法在其上运行的实例的指针,是const。这意味着它不能修改字段,只能在其上调用const方法 ,而不是通常的方法。

完全可以接受调用自由函数,甚至可以在同一类的不同对象上调用非const方法,只要该对象不是{{1} }。

答案 3 :(得分:0)

考虑这个

using Android.Graphics.Drawables;
using Android.OS;
using Android.Support.V4.App;
using Android.Views;
using Android.Webkit;
using Android.Widget;

namespace BottomNavigationViewPager.Fragments
{
    public class TheFragment1 : Fragment
    {
        string _title;
        string _icon;

        protected static WebView _wv;

        public static TheFragment1 NewInstance(string title, string icon) {
            var fragment = new TheFragment1();
            fragment.Arguments = new Bundle();
            fragment.Arguments.PutString("title", title);
            fragment.Arguments.PutString("icon", icon);
            return fragment;
        }

        public override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            if (Arguments != null)
            {
                if(Arguments.ContainsKey("title"))
                    _title = (string)Arguments.Get("title");

                if (Arguments.ContainsKey("icon"))
                    _icon = (string)Arguments.Get("icon");
            }
        }

        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {

            var view = inflater.Inflate(Resource.Layout.TheFragmentLayout1, container, false);

            _wv = view.FindViewById<WebView>(Resource.Id.webView1);

            var _wvc = new MyWebViewClient();




            _wv.SetWebViewClient(_wvc);

            //string _wtf = "header";



            _wv.Settings.JavaScriptEnabled = true;

            _wv.Settings.AllowFileAccess = true;

            _wv.Settings.AllowContentAccess = true;




            //_wvc.OnPageFinished(_wv, _jsHideBannerC);



            _wv.LoadUrl("https://www.duckduckgo.com/");

            return view;
        }

        private class MyWebViewClient : WebViewClient
        {
            public override void OnPageStarted(WebView view, string url, Android.Graphics.Bitmap favicon)
            {
                base.OnPageStarted(view, url, favicon);


            }

            public override void OnPageFinished(WebView view, string url)
            {
                base.OnPageFinished(view, url);


                string _jsHideBanner = "javascript:(function() { " +
                                "document.getElementById('content_homepage').style.display='none'; " + "})()";

                string _jsHideBannerC = "javascript:(function() { " +
                    "document.getElementsByClassName('logo-wrap--home').style.display='none'; " + "})()";

                _wv.LoadUrl(_jsHideBanner);
            }


        }
    }
    }

每当您在#include <iostream> int f(int num) { return num+1; } int fr(int& num) { return num+1; } int fcr(const int& num) { return num+1; } class D { public: int value= 0; public: void f1() { value++; } int f2() const { return value; } int f3() { return value; } static void f4() { std::cout << "Hello" << std::endl; } void f5() const; }; void D::f5() const { // Prohibited: // f1(); // modifies this // f3(); // might modify this // value++; // modifies this->value, thus modifies this // value= 2; // modifies this->value, thus modifies this // value= abs(value); // modifies this->value, thus modifies this // fr(value); // takes value by reference and might modify it // // Permitted: f2(); // const function, does not modify this std::cout << value << std::endl; // independent function, does not modify this; read access to this->value is const std::cout << abs(value) << std::endl; // independent function, does not modify this; read access to this->value is const f4(); // static function, does not modify this f(value); // function, does not modify this; takes value as read only (makes copy) fcr(value); // function, does not modify this; takes value as read only by reference D otherObject; otherObject.f1(); // modifies otherObject (non const), does not modify this } int main() { const D d; d.f5(); } 内调用诸如f4()之类的成员函数时,都会传递与f5()等效的隐式this指针。在this->f4()内部,f5()的类型不是const,而是D*。因此,您无法进行const D*(相当于value++的{​​{1}}。但是您可以呼叫this->value++const D*或任何不需要{{ 1}},然后尝试对其进行修改。)

如果abs的类型为printf,则选择this时,其类型为this->value,您可以自由对其进行修改。如果对this执行相同的操作,其类型将变为D*,则无法对其进行修改,但可以将其复制并作为const引用进行访问以供读取。