我想知道,如果它能够让我们编译器问题的一个警告/错误的代码如下:

注:

1.是啊,这是不好的编程方式和我们应该避免这样的情况,但我们正在处理遗留码,并希望编译器,可以帮助识别这种情况下我们。)

2.我喜欢一个编译器的选择(VC++)禁用或使对象的切片,如果有任何。

class Base{};
class Derived: public Base{};

void Func(Base)
{

}

//void Func(Derived)
//{
//
//}

//main
Func(Derived());

在这里,如果我出评论的第二项功能,第一个函数就叫-和编译器(两VC++和海湾合作委员会)的感觉舒服。

它是用C++标准?和我可以问compiler(VC++)给我警告的时候遇到过这样的代码?

感谢这么多!

编辑:

感谢所有这么多对于你的帮助!

我不能找到一个编译器的选择得到error/warning-我甚至发布该在MSDN论坛VC++编译器顾问没有答案。所以我既不害怕海湾合作委员会也不vc++实现这一功能。

因此添加的构造而采取的派生类为放慢参数将会是最好的解决办法。

编辑

我有提交feedbak MS并希望他们将修复它很快:

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=421579

-白燕

有帮助吗?

解决方案

如果你可以修改的基类你能做些什么,如:

class Base
{
public:
// not implemented will cause a link error
    Base(const Derived &d);
    const Base &operator=(const Derived &rhs);
};

根据编译器,应该得到你的翻译单位,也许能在那里的切片是在发生的事情。

其他提示

作为一个变化 安德鲁Khosravian的答案, 我会建议使用模板的复制构造和分配运营商。这样你不需要知道的所有源类别的定基类为了保护这一基类反对切割:

class Base
{
private:   // To force a compile error for non-friends (thanks bk1e)
// Not implemented, so will cause a link error for friends
    template<typename T> Base(T const& d);
    template<typename T> Base const& operator=(T const& rhs);

public:
// You now need to provide a copy ctor and assignment operator for Base
    Base(Base const& d) { /* Initialise *this from d */ }
    Base const& operator=(Base const& rhs) { /* Copy d to *this */ }
};

虽然这可减少所需的工作量,这种方法还需要与每个基类为了保障。此外,它将会造成问题,如果有合法的转换 BaseSomeOtherClass 雇用一个 operator Base() 成员 SomeOtherClass.(在这种情况下,一个更详细的解决方案,涉及 boost::disable_if<is_same<T, SomeOtherClass> > 可以使用。) 在任何情况下,应该删除这个代码一旦你确定所有实例的对象的切片。

编译器实现的世界: 测试对象的切片是肯定的东西,可能是有价值的创造(可选)警告!我不能想到的一个实例,其中将它所需的行为,这是非常常看到的在新手C++编码。

[编辑27/3/2015:] 如指出的那样,马特*麦克,你其实不需要声明的复制构造和分配运营商明确,因为我已经做了上述,因为他们仍然会被隐含地宣布,通过编译器。在2003年C++的标准,这是明确地提到在脚注106下的12.8/2:

因为一个模板构造永远不会是一个复制的构造,存在这样一个模板不抑制了隐性声明的副本构造。模板构造参与过载决议与其他的构造,包括复制的构造,以及一个模板构造可用于复制目的,如果它提供了一个更好的匹配于其他的构造.

我建议增加一个构造你的基类需要一常量的参考来源类明确地(以前的宣言).在我的简单测试的应用程序,这个构造变得称在切的情况。你可以那么至少得到一个运行时间的说法,你可能可以得到一个编译时的说法与聪明的使用的模板(例如:化模板的方式,生成一个编译时断言,constructor).还可以编译器的具体方式获得汇编时的警告或错误,当你打电话明确的职能;例如,可以使用"声明影响(deprecated)"的"片的构造"在Visual Studio得到一个编译时警告,至少在功能呼叫的情况。

所以在你的例子,代码看起来会像这样(Visual Studio):

class Base { ...
    __declspec(deprecated) Base( const Derived& oOther )
    {
        // Static assert here if possible...
    }
...

这一工作在我的测试(编译时警告).注意,它没有解决的副本的情况,但一个同样构分配运营人应该做的伎俩。

希望这会有所帮助。:)

这通常被称为 对象的切片 而是一个知名的足够的问题有其自己的文章(虽然它只是一个简短的说明的问题)。

我相信我有用的一个编译器,有一个警告可以启用以检测并发出警告这一点。然而,我不记得其中一个。

不是真正的解决方案的立即的问题,但是....

大多数功能,采取类/struct对象的参数应该声明的参数类型的"const X"或"X",除非他们有一个很好的理由。

如果你总是做这个,对象切将永远是一个问题(参考文献没有得到切!).

最好的方式来打击这个问题通常是跟着斯科特迈尔的建议(见 有效C++)只具有具体的类在叶节点继承树,并确保非叶类的抽象具有至少一个纯粹的虚拟功能(析构,如果没有其他).

令人惊讶的是经常这种做法有助于澄清在设计其他的方式,作为良好。努力的隔离一个共同的抽象的界面通常是一个值得设计的努力,在任何情况下。

编辑

虽然我本来并没有明确这一点,我的答案来自一个事实,即这是不可能的警告,准确的有关对象的切片在汇编时间和出于这个原因,它可能导致一种虚假的安全感,如果你有一个编译时断言,或者一个编译器的警告启用。如果你需要找出关于实例的对象切和需要纠正他们,那么它意味着你有愿望和有能力改变旧的代码。如果是这种情况,那么我认为你应该认真考虑重构类层次作为一种方式使代码的更多强大。

我的推理是这样的。

考虑到一些图书馆的代码的定义类Concrete1和使用其在该接口,这一功能。

void do_something( const Concrete1& c );

通过该类型的参考是提高效率和是,在一般情况下,一个好主意。如果库认为Concrete1是一个值类型的执行情况的可能决定做一个复制的输入参数。

void do_something( const Concrete1& c )
{
    // ...
    some_storage.push_back( c );
    // ...
}

如果对象类型通过参照的是,事实上, Concrete1 而不是其他一些源类型,然后这种代码是好的,没有切片进行。一般警告在这 push_back 功能援引可能只产生误报,最有可能是无益的。

考虑到一些客户的代码来 Concrete2Concrete1 并将它变成另一个函数。

void do_something_else( const Concrete1& c );

因为参数,采取的是参考不切发生在这里的参数检查,因此它是不正确的提醒这里的一切,因为它可能是,没有一切的发生。通过在一个源类型的功能,需要一个基准或指针是一个共同的和有益的方式利用多态的类型所以警告或禁止这似乎将产生相反的效果。

那么,是有错误?好的'错误'是通过在一个参考的东西是从一个类,然后处理,因为尽管它是一个值类型的所谓的功能。

还有,在一般情况下,没有办法生成一致的有用的汇编时警告针对的对象切,这就是为什么最好的辩护,如有可能,是消除该问题通过的设计。

class Derived: public Base{};

你说来是一个基地,因此它应该在的任何功能,需要一个基础。如果这是一个真正的问题,也许继承不是你真的想要使用。

我修改你的代码略:

class Base{
  public:
    Base() {}
    explicit Base(const Base &) {}
};

class Derived: public Base {};

void Func(Base)
{

}

//void Func(Derived)
//{
//
//}

//main
int main() {
  Func(Derived());
}

明确的关键词将确保构造将不会被用作一种隐性转换操作员-你必须呼吁它明确,当你想要使用它。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top