C++通过继承在受保护的构造函数的基类堆上分配对象

Ste*_*phQ 6 c++ inheritance

我有一个带有受保护构造函数的类:

class B {
protected:
    B(){};
};
Run Code Online (Sandbox Code Playgroud)

现在我从它派生并定义了两个静态函数,我设法实际创建了类B的对象,但不是在堆上:

class A : public B {
public:
    static B createOnStack() {return B();}
    //static B* createOnHeap() {return new B;} //Compile time Error on VS2010
};

B b = A::createOnStack(); //This works on VS2010!
Run Code Online (Sandbox Code Playgroud)

问题是:1)VS2010在允许第一种情况下是错误的吗?2)是否可以在不修改B的情况下创建B的对象(没有友谊,也没有额外的功能).我问,因为在处理B及其成员函数的实例时可以做出类似的事情,请参阅:http: //accu.org/index.php/journals/296

提前感谢您的任何建议!

亲切的问候

zeu*_*xcg 5

  1. 是的,此代码不符合要求.这与受保护成员访问的特殊规则有关(C++ 03 draft,11.5/1):

    当派生类的朋友或成员函数引用受保护的非静态成员函数或受保护的基类的非静态数据成员时,除了先前在第11.10节中描述的那些之外,还应用访问检查.除非形成指向成员的指针(5.3.1),否则访问必须通过指向,引用或派生类本身的对象(或从该类派生的任何类)(5.2.5).

    当您使用B()或new B()时,您通过指向基类的指针有效地使用构造函数.

  2. 您可以创建A类型的对象(我假设A是已发布的 - 没有其他成员/非静态函数)并使用它.如果你在堆栈上创建它,一切都应该正常工作,除非你试图为它分配其他类型的B对象.如果你在堆上创建它,只要B的析构函数是虚拟的,一切都很好.如果B的析构函数不是虚拟的,并且您将新的A()作为B*返回,那么删除指针在技术上是未定义的行为(5.3.5/3:

    在第一个替代(删除对象)中,如果操作数的静态类型与其动态类型不同,则静态类型应为操作数的动态类型的基类,静态类型应具有虚拟析构函数或行为未定义.

    但是你可能会发现它在实践中运行良好,所以如果没有其他的解决方法你可以依赖实际行为(即将它作为最后的手段).