【问题标题】:How to prevent default initialization of a const variable with a class type如何防止默认初始化具有类类型的 const 变量
【发布时间】:2012-01-01 05:03:29
【问题描述】:

我有一个自定义类,我希望它的行为类似于内置类型。

但是我注意到您可以在不提供初始值的情况下初始化该类的 const 变量。我的班级目前有一个空的默认构造函数。

这是 int 和我的类 foo 的比较:

int a;              // Valid
int a = 1;          // Valid
const int a = 1;    // Valid
const int a;        // Error

foo a;              // Valid
foo a = 1;          // Valid
const foo a = 1;    // Valid
const foo a;        // Should cause an error, but it compiles

如你所见,我需要阻止

const foo a;

来自编译。

C++ 大师有什么想法吗?

【问题讨论】:

    标签: c++ initialization constants initializer default-constructor


    【解决方案1】:

    C++ 的规则只是简单地说默认初始化(例如new T;)和值初始化(例如new T();)对于类类型的对象是相同的,但对于基本类型的对象则不然。

    您无法“覆盖”这种区别。它是语法的基本部分。如果你的类是可值初始化的,那么它也是可默认初始化的。

    没有任何用户定义的构造函数的类有一种例外:在这种情况下,成员的初始化是递归完成的(因此,如果您默认初始化对象,它会尝试默认初始化所有成员),并且如果任何类成员本身是基本的,或者再次具有这种性质,这将失败。

    例如,考虑以下两个类:

    struct Foo { int a; int b; };
    struct Goo { int a; int b; Goo(){} };
    
    //const Foo x; // error
    const Goo y;   // OK
    

    Foo 的隐式构造函数被拒绝,因为它没有初始化基本成员。但是,y 很高兴默认初始化,y.ay.b 现在“故意留空”。

    但除非您的类没有任何用户定义的构造函数,否则这些信息对您没有帮助。您不能将初始化类型“转发”给成员(例如 Foo() : INIT_SAME_AS_SELF(a), b() { })。

    【讨论】:

    • 第一句中,fundamental type应该改为POD type,其中包括基本类型和其他适合的类型——一定程度上——你在第三段中的描述。另请注意,第三段也没有准确描述哪些类型属于该类别:基本类型成员的存在不会改变行为,而是不存在一个非 POD 成员,并且它还缺少一个事实,即只有基本类型 和虚函数 的类型也将暗示 new T;new T(); 是等价的。 .
    • @DavidRodríguez-dribeas:不,POD 不对。您的班级很可能有非 POD 成员并且仍然以这种方式行事。也许是“聚合”,但我认为这只是缺少用户构造函数。例如。拥有析构函数不会改变这一点。尝试添加 std::string 成员或析构函数。我认为使用隐含构造函数的递归定义是最通用和简洁的。
    • @DavidRodríguez-dribeas:我认为你所说的任何一个都不正确:试试struct Foo { std::string a; virtual void f() { }; ~Foo() {} }; 现在const Foo x; 仍然不起作用,但const Foo x{}; 可以。
    • struct test1 { std::string s; int i; }; const test1 t; 编译。 struct test2 { int i; virtual void f() {} }; const test2 t; 编译。你是对的,析构函数不会影响问题,所以 POD 不是最好的定义,但你上面的定义也不是。您在上一条评论中提供的示例对我(g++4.6,c++03 模式)和 c++ 和 c++11 模式下的 ideone 编译得很好。你试过什么编译器?
    • @DavidRodríguez-dribeas:这是 GCC 4.6.2,有或没有 -std=c++0x
    【解决方案2】:

    只有当它有一个默认构造函数时它才会编译,它编译是因为它有它,这意味着它被初始化了。如果您不希望编译该行,只需禁用默认构造函数(也会使foo a; 成为错误,作为不需要的副作用)。没有foo的定义或者你想做什么,这是我能得到的。

    我认为没有任何方法可以实现您想要的(即允许默认初始化非常量变量,同时让 const 版本编译失败并允许其他用例——需要提供构造函数)

    【讨论】:

    • 你可以保护默认构造函数。
    • @arne:我看不出这有什么帮助。默认构造函数可以访问并且foo a; const foo a; 都可以编译,或者它不是并且都不编译。此外,protected 可能不是最好的方法,因为问题中没有继承,自然选择public 授予访问权限,private 禁止访问。
    • @arne:那会实现什么? protected 可见性仅在继承场景中有用。
    猜你喜欢
    • 2015-12-05
    • 2015-08-01
    • 2015-08-19
    • 2019-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-07
    相关资源
    最近更新 更多