2016-07-22 24 views
2

我遇到了对象切片的奇怪情况。我正在处理需要单例类的项目,所以我的基类和派生类都是单例类。以下示例案例描述了我的情况。对基类静态引用数据成员的C++对象切片行为的奇怪情况

这是我的基类

// Base.h 
class Base 
{ 
    public: 

     static Base& base; 

     virtual void doSomething(){ cout<<"Base Do Something"<<endl; } 

    protected: 

     Base(); 
     virtual ~Base(); 
     static Base& getBaseInstance(); 

    private: 
}; 

//Base.cpp 
Base::Base() 
{ 
    //ctor 
} 

Base::~Base() 
{ 
    //dtor 
} 

Base& Base::getBaseInstance() 
{ 
    static Base object; 
    return object; 
} 
Base& Base::base=Base::getBaseInstance(); 

这是我的派生类

class Derived: public Base 
{ 
    public: 

    static Derived& derived; 
    virtual void doSomething(){ cout<<"Derive Do Something"<<endl; } 

    static Derived& getDerivedInstance(); 
    protected: 
     Derived(); 
     virtual ~Derived(); 

    private: 
}; 

Derived::Derived() 
{ 
    //ctor 
} 

Derived::~Derived() 
{ 
    //dtor 
} 

Derived& Derived::derived=Derived::getDerivedInstance(); 

Derived& Derived::getDerivedInstance() 
{ 
    static Derived object; 
    return object; 
} 

最后,这是我的主要功能

int main() 
{ 
    cout << "Hello world!" << endl; 
    Base::base.doSomething(); 
    Derived::derived.doSomething(); 

    Base::base=Derived::derived; 

    Base::base.doSomething(); 

    Base::base=Derived::getDerivedInstance(); 

    Base::base.doSomething(); 

    Base& r = Derived::derived; 

    r.doSomething(); 

    Base::base=Derived::getDerivedInstance(); 
    Base::base.doSomething(); 
    return 0; 
} 

而且我正在为这个下面的输出

Hello world! 
Base Do Something 
Derive Do Something 
Base Do Something 
Base Do Something 
Derive Do Something 
Base Do Something 

所以我的问题是因为对象切片不应该在引用上工作,那么为什么我不能覆盖Base::base引用我创建为带有Derived对象的基类的静态数据成员?虽然这工作正常Base& r = Derived::derived;

我的意思是当我打电话做一些事情r.doSomething()我得到doSomething派生类。但事实却不是这样与

Base::base=Derived::derived;  
    Base::base.doSomething(); 

Base::base=Derived::getDerivedInstance();  
    Base::base.doSomething(); 

任何类型的澄清将不胜感激。 谢谢。

+0

您不能辞职。如果它看起来像你那么正在发生的是切片。 –

+0

谢谢队友。我犯了这样一个愚蠢的错误(自2晚以来的编码,我想我应该睡觉)再次感谢。 –

回答

3

当你

Base::base=Derived::derived; 

您没有设置基准参考来引用派生类。这是赋值运算符,它所做的全部是将derivedBase部分与base对齐。

base仍然Base型的,从来没有改变,因为引用永远只能初始化一次,你做到这一点与

Base& Base::base=Base::getBaseInstance(); 

如果你想要这个再分配行为,你将需要使用一个指针类型。

+0

哦,我完全忘记了只能初始化一次引用的事实。再次感谢。 –

+1

@ Dr.Xperience没问题。乐意效劳。 – NathanOliver

1

引用是为了所有目的引用的对象。分配给参考是分配给参考的对象。在你的情况下,对象没有数据成员,所以没有任何影响。

特别是没有可检测到的切片。

声明

Base& r = Derived::derived; 

&hellip;是一个非常不同的情况:初始化,而不是分配。

初始化使引用引用指定的对象。

此后无法更改参考。


其他消息:

  • 全局变量(引用)运行静态初始化顺序的悲剧的风险。它们只是为了消除单身吸气剂功能的优点。对于全局函数,这些函数只是没有用处而增加了详细程度。

  • 具有数据成员的可变单例允许在代码的广泛分离和看似没有连接的部分之间进行通信。这使得很难依赖关于当前状态的任何假设以及什么影响什么。这也是为什么在每种编程语言中全局变量都被认为是邪恶的™,所以谨慎使用单例。

+0

这只是一个例子。我的实际案例在派生类中有很多成员。感谢帮助。我犯了这样一个愚蠢的错误。 –

+0

我的项目只有两个单身人士。他们充当服务提供者。尽管对于驱动程序服务提供商来说,开销很大。 –

1

Base::base是一个静态参考。在这里,您intialize它:

Base& Base::base=Base::getBaseInstance(); 

从这时开始(即使用base执行代码之前),base指基实例(即在Base::getBaseInstance()声明的静态实例)。

然后,当您完成作业后,将不再更改参考,但是您会将对象复制到由base(其类型为base,因此为切片!)引用的对象中。

解决方法可能是使base :: base指针。通过这种方式,您可以将其更改并指向派生对象。然而,这是否符合我们的单例方法(因为那样你就会有基础对象和派生对象)。

+0

重新“因此切片”,没有数据成员,因此不可能检测到切片。 –

+0

谢谢队友,我知道指针方法。只要避免它具有最少数量的迹线(英特尔迹线/预解码)。再次感谢。 –

+0

@ Cheersandhth.-Alf可能没有数据成员,但有虚拟功能。由于作业是关于普通对象的,Derived类型会丢失,所以它不再使用预期的虚拟函数。我不是natike英语人士:当有些信息丢失时,我使用“切片”[使用此定义](http://stackoverflow.com/questions/274626/what-is-object-slicing),但可能是你可以提出一个更好的措辞。 – Christophe

相关问题