C++里的`::`作用域运算符和`.`运算符怎么总感觉有点奇怪? - V2EX
codechaser
V2EX    C

C++里的`::`作用域运算符和`.`运算符怎么总感觉有点奇怪?

  •  
  •   codechaser Apr 11, 2019 3993 views
    This topic created in 2589 days ago, the information mentioned may be changed or developed.

    各位好!百度了一下也不是太清楚:

    #include <iostream> #include <memory> using namespace std; class A { public: typedef shared_ptr<A> Ptr; int a = 10; void test(){ std::cout << a << std::endl; } }; int main() { A foo; cout << foo.a << endl; A::Ptr bar; //cout << A::a << endl; //foo.Ptr c; } 

    假如这里Ptr被当成类型,它算不算一个实例变量呢?注释的两行都是不可以的。我看很多都是这样写的,那我为什么不在要用Ptr的时候在类外面需要的时候定义?typedef shared_ptr<A> Ptr再用也没错啊。

    18 replies    2019-04-19 19:41:00 +08:00
    429839446
        1
    429839446  
       Apr 11, 2019
    这好像是依赖类型, 典型的像 stl 容器里面的各种类型, ::value_type, ::iterator, ::const_interator 之类, 加了类的命名空间可以防止冲突. 在泛型或者模板元的时候, 可以直接获取这些类型做一些操作. 另外类静态方法和静态变量可以. 访问也可以::访问, 为了显示指出这一点,我一般用后者访问
    across
        2
    across  
       Apr 11, 2019 via iPhone
    typedef 相当于增加个别名,Ptr 和 shared_ptr<A>一个意思。
    这么想,反正 . 前面的就是个实例。
    wevsty
        3
    wevsty  
       Apr 11, 2019   1
    ::前面的是命名空间的名字,后面可以是类型,也可以是函数。
    .前面是一个具体类型的实例,后面是这个实例对应的成员,成员函数。
    zealot0630
        4
    zealot0630  
       Apr 11, 2019
    这是 C++以及众多语言的设计缺陷之一,滥用 static 概念。

    未防止歧义,我用 /代表 . 或者 ::

    1. foo/Ptr 和 bar/Ptr 是同一个东西么?是,所以本质上 Ptr 是属于类的。
    2. foo/a 和 bar/a 是同一个东西么?不是,所以本质上 a 是属于对象的。

    访问类内东西使用 ::
    访问对象内东西使用 .
    GjriFeu
        5
    GjriFeu  
       Apr 11, 2019
    @zealot0630 那如果我定义的是 static int a; foo/a 和 bar/a 是同一个东西么?是
    zealot0630
        6
    zealot0630  
       Apr 11, 2019 via Android
    是啊 所以要用 类::a 访问
    Yggdroot
        7
    Yggdroot  
       Apr 11, 2019
    首先,你要搞清楚,Ptr 是 typedef 的一个类型,不是实例变量,比如可以认为 Ptr 是个 int,这样就不会糊涂了。注释里的 foo.Ptr 这种写法,就像写 foo.int 一样,明显是不对且无意义的。

    > 那我为什么不在要用 Ptr 的时候在类外面需要的时候定义? typedef shared_ptr<A> Ptr 再用也没错啊

    你这样也没错,定义在类里面,只是作用域在类里面,对外面不可见,如果外面想访问,必须指定作用域,也就是 A::Ptr。

    A::a 不可以这样,是因为 a 不是静态变量,静态变量是属于类的,故可以写成 A::a。非静态变量是属于每个实例的,不可以写成 A::a。
    Yggdroot
        8
    Yggdroot  
       Apr 11, 2019
    @zealot0630 > 1. foo/Ptr 和 bar/Ptr 是同一个东西么?是,所以本质上 Ptr 是属于类的。

    他们是同一个东西,因为他们都是错误写法。因为 Ptr 是个类型,而不是变量,不存在变量 /类型这种写法。
    eret9616
        9
    eret9616  
       Apr 11, 2019
    typedef 在编译阶段将 shared_ptr 加上 Ptr 这个别名

    进入 main 函数开始执行,

    A::Ptr bar;

    这句话是声明变量, 数据机构是类 A 中 Ptr , 在栈上分配,这个变量名是 bar

    A::a 是声明变量 所以不能 cout

    foo 是实例化的对象... 不要和声明搞混啊
    eret9616
        10
    eret9616  
       Apr 11, 2019
    另外看不懂楼上们在说什么...
    missdeer
        11
    missdeer  
       Apr 11, 2019 via Android
    7 楼正解
    shoujiaxin
        12
    shoujiaxin  
       Apr 11, 2019 via iPhone
    @zealot0630 请教一下,为什么 . 和 :: 是设计缺陷呢?以及它们和 static 概念有什么关系?没太搞明白
    GeruzoniAnsasu
        13
    GeruzoniAnsasu  
       Apr 12, 2019   2
    hhhhhh 建议暂时先记住用法,这块能展开的东西多了去

    ::这个符号跟 C++最邪恶晦涩的部分( templates )紧密相关,但简单来说,他只有一个含义,就是“属于 namespace ”

    A::a 这个语法,在 C++里,是 ambiguous 的,唯一能确定的是,a 在 A namespace 中(如果把 class 也看做是 namespace 的话),所以先不要先入为主认为 A::a 一定是表示变量或者类型,实际上 A 也好 a 也好,它们可以是变量,可以是类型,甚至还可以是一个 incomplete type (在类型推导中),一个最令人颤抖的例子是 STO 上关于 C++语言是否是 context-free 的讨论:
    https://stackoverflow.com/questions/14589346/is-c-context-free-or-context-sensitive

    由于 C++的 templates 是 Turing Complete 的,所以,推导 A::a 的 a 到底是什么东西,的这个过程,是 Turing Complete 的,理论上你可以写出一个“推测出 a 是什么东西的时候处理完一次 HTTP 请求”这样的程序

    与之相比,A.a,必定代表 访问 对象 A 的成员 a,a 一定被绑定到实例 A,这个 syntax 是不存在歧义性的



    然后至于为什么要有::这种东西
    这么说,当你不需要用 templates 的时候,它仅仅表示一个名字所属的限定,真的没什么用,你甚至可以手动 A_B_c 这样子从命名上划分 namespace
    但用到 templates 的时候,模板有一个决定性的特性是
    A<特化 1>::v

    A<特化 2>::v
    可以不同,但不同的 v 都可以用同一个 dependent type 去使用,这个时候 A<T>::v 的 v 是什么取决于 T,而 T 是可随着模板实例化位置的上下文不同,会自动改变的!这个时候可以说::的作用是使一个 type 能够依赖于另一个 type,而这也编译期多态的关键



    展开太多估计也看不懂,而且我表达得也很可能不准确。
    四点:
    c++里 value 和 type 永远是俩种东西,不存在 python 中“ class 是 type object ”这么混沌的语义
    c++里::这个运算符仅仅表示 namespace 所属,左右两边到底是 type 还是 value 都有可能
    就你的例子来说 typedef 在外面当然可以,但定义在里面的 dependent type 肯定是有自己作用的
    static 变量其实就是把它所在的 class 看做一个 namespace,它自己是这个 namespace 下的变量,对比一下全局变量和 namespace 中的“全 namespace 变量”就明白了
    wutiantong
        14
    wutiantong  
       Apr 12, 2019
    @GeruzoniAnsasu 很深入的回复,其实还可以提一下 ADL。。。
    wutiantong
        15
    wutiantong  
       Apr 12, 2019
    学编程还是别“百度一下”了,直接上 https://stackoverflow.com 应该不用翻墙
    codechaser
        16
    codechaser  
    OP
       Apr 12, 2019 via Android
    @GeruzoniAnsasu 感谢!因为之前主要用 python 和 java,最近转学 c++,照着写代码总感觉这个"::"充满不解
    codechaser
        17
    codechaser  
    OP
       Apr 12, 2019 via Android
    @wutiantong 百度一下只是习惯
    LGA1150
        18
    LGA1150  
       Apr 19, 2019
    @wutiantong 然而 StackOverflow 的图床 Imgur 被墙了
    About     Help     Advertise     Blog     API     FAQ     Solana     5547 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 656ms UTC 08:37 PVG 16:37 LAX 01:37 JFK 04:37
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86