Why can't redefine type names in class in C++?

前端 未结 3 1246
星月不相逢
星月不相逢 2020-12-03 23:28

According to the book C++ Primer section, 7.4.1 Type Names Are Special:

Ordinarily, an inner scope can redefine a name from an outer scope even if tha

3条回答
  •  一生所求
    2020-12-04 00:12

    I would like to try to answer some questions from your comments.

    Comment 1

    "But in the function main, we can redefine typedef double Money even if it is defined after the statement Money asset"

    So you are asking, why typedef identifier can be defined more than once in a non-member function(in a non-class scope)?

    The answer is here:Repeated typedefs - invalid in C but valid in C++?

    Comment 2

    So, in this example, two Foos with different meaning both lexically precede the statement Foo b = a in function meow. Then the compiler can't determine which the type of b is. Is it correct or not?

    The complier can determine the type of b in that code chunk. B's type is obvisouly char* while the type of a is int.

    Although two Foo with different meaning both lexically precede the statement Foo b = a in function meow, Foo defined as int precedes Foo defined as char*. The book says that the name lookup process is different:

    • First, the member declarations are compiled.
    • Function bodies are compiled only after the entire class has been seen.

    So in the first step, while compiling member declarations, Foo a and using Foo = char* get compiled in order. And the first Foo uses outside definition of Foo, which is int. Then, an inner scope Foo is created, with type char*. After that, the compiler starts to compile the function body. For function meow, Foo b uses inner scope Foo, which is char*, while for a, which is already get compiled in the first step, is a int Foo. So that's how the conversion error occurs.

    Comment 3

    I want to know is that why "the class may not subsequently redefine that name." But "an inner scope can redefine a name from an outer scope even if that name has already been used in the inner scope." –

    R Sahu's point (and I think it is what the book wants to say) is that if you really want to redefine a typedef identifier, you can only do this in the very beginning of your class. So there won't be any "ambiguity" about that identifier among the context.

    Summary:

    Allow this:

    (This can't compile in g++ (because standard ban this) but can in Visual Studio, because logically there's no conflict here.)

    typedef double Money;
    class Account {
        public:
            Money balance() { return bal; }
        private:
            typedef double Money;
            Money bal;
    };
    

    is very easy to cause things like this:

    (can't compile in both g++ and Visual Studio, because logically there is conflict here.)

    using Foo = int;
    
    struct X {
        Foo a;    // ::Foo, i.e., int
        void meow() { 
            Foo b = a; // X::Foo; error: no conversion from int to char*
        }
        using Foo = char*;
    };
    

    so if you really want to redefine a typedef identifier inside a class. Only do this:

    (can compile in both g++ and Visual Studio, because logically there's no conflict here and standard only allows this.)

    typedef double Money;
    
    class Account {
        public:
            typedef double Money;  
            //put the redefine statement in the very beginning
            Money balance() { return bal; }
        private:
            Money bal;
    };
    

    PS:

    Explain the code:

    typedef double Money;
    class Account {
        public:
            Money balance() { return bal; }
        private:
            typedef double Money;
            Money bal;
    };
    

    These code is logically right but for standard it is banned. Same compiling step as mentioned above, first compile function balance's declaration, so Money here is the outside Money. Then complie typedef double Money we get a inner scope Money and the type of bal is Account::Money not the outside one.

    So practically you can do this with Visual Studio compiler but not with g++:

    typedef double Money;
    class Account {
        public:
            Money shit = 12.34; //outside money, type is double
        private:
            typedef string Money;  
            Money bal;   //bal is string not double
    };
    

    Thanks for the enlightenment from the other two answers. And there's some prediction in my post which is my personal deduction. If there's anything wrong, feel free to correct it.

提交回复
热议问题