我想知道是否可以在基本构造函数调用的函数内调用派生类函数(当括号中的代码执行时,是否已经创建了它?)
#pragma once
class ClassA
{
public:
ClassA(void);
virtual ~ClassA(void);
void Init();
protected:
short m_a;
short m_b;
virtual void SetNumbers(short s);
};
include "ClassA.h"
#include <iostream>
ClassA::ClassA(void) : m_a(0), m_b(0)
{
Init();
}
ClassA::~ClassA(void)
{
}
void ClassA::SetNumbers(short s)
{
std::cout << "In ClassA::SetNumbers()\n";
m_a = s;
m_b = s;
}
void ClassA::Init()
{
this->SetNumbers(2);
}
#pragma once
#include "ClassA.h"
class ClassB : public ClassA
{
public:
ClassB(void);
virtual ~ClassB(void);
virtual void SetNumbers(short);
int x;
};
#include "ClassB.h"
#include <iostream>
ClassB::ClassB(void)
{
}
ClassB::~ClassB(void)
{
}
void ClassB::SetNumbers(short s)
{
std::cout << "In ClassB::SetNumbers()\n";
m_a = ++s;
m_b = s;
ClassA::SetNumbers(s);
}
有任何建议吗?...
提前谢谢你:) ...
答案 0 :(得分:2)
你不能这样做的原因很简单,即在构造基类时,派生类甚至还没有开始构造。您不能在尚不存在的对象上调用成员函数。
实际上,即使你设法调用SetNumbers
并在初始化之前分配派生类的成员变量,它们肯定会在最终初始化时被覆盖。我承认对此进行推理是没有意义的,因为我们在定义的行为之外会很好。
答案 1 :(得分:2)
没有。 B的所有部分(以A开头,因为它的基础)是在调用B的构造函数之前构造的。因此,在调用SetNumbers
时,B的任何部分(A部分除外)都没有构建 - 并且可能包含v表,因此无法知道该调用的去向去吧。
当然,有一个简单的解决方案:从B的构造函数中调用B :: SetNumber()(毕竟,B的构造函数的目的)
答案 2 :(得分:1)
不,抱歉。 :(它可能在一个或两个C ++编译器中编译,但不推荐。来自C++ FAQ Lite section 10.7:
[10.7]你应该使用这个指针吗? 在构造函数中?
[...剪断...]
这是永远不会有效的事情: 构造函数的{body}(或者 从构造函数调用的函数) 无法归结为派生类 调用虚拟成员函数 在派生类中重写。如果 你的目标是达到被覆盖的目标 你在派生类中的函数 不会得到你想要的。请注意你 将无法进入覆盖 派生类独立于你 调用虚拟成员函数: 显式使用this指针 (例如,this-&gt; method()),隐含地 使用这个指针(例如, method()),甚至调用其他一些 调用虚拟成员的函数 对你的这个对象起作用。该 底线是这样的:即使 调用者正在构建一个对象 派生类,在构造函数中 基类的,你的对象不是 那派生的课程。你有 被警告过。
注意:强调我的。
链接的更多详情
答案 3 :(得分:1)
唯一可以做到这一点的是从某个模板派生出来的东西:
template<typename T> class base
{
T* down_cast() throw()
{
return static_cast<Derived*>(this);
}
const T* down_cast() const throw()
{
return static_cast<const Derived*>(this);
}
public:
base()
{
down_cast()->doSomething();
}
/* … */
};
class derived : private base<derived>
{
public:
void doSomething()
{
}
};
请注意,doSomething
是公开的而非虚拟的。
我们可以将static_cast导出,因为已知派生是派生类型。
从基础参数化中获取某些东西是最好的时候做的奇怪的事情。据说,当微软的ATL团队使用它时,他们问C ++编译器团队是否有效并且没有人确定,尽管它是有效的,因为模板构造依赖于名称如下:
首先,模板可用,但不在类中使用。然后,名称derived
可用。然后它实例化base<derived>
的布局 - 这需要知道成员变量和虚函数,只要这些都不依赖于derived
布局的知识(指针和引用很好),这将是一切顺利。然后它将创建derived
的布局,最后它将创建derived
的成员函数,其中可能包括为base<derived>
创建成员函数。因此,只要base<derived>
不包含派生成员变量(基类永远不能包含从自身派生的类型的成员变量)或需要知道派生的布局的虚函数,我们确实可以做到冒险 - 看上面的遗产。
这包括能够在施工期间从derived
调用base
的非虚拟公共成员,因为它已经是基础的一部分。这有很大的局限性。特别是,如果doSomething()
依赖于derived
构造函数中构造的任何内容,那么它将无效,因为derived
尚未构建。
现在,这真的是个好主意吗?否。
答案 4 :(得分:0)
一个简单的设计解决方案是使用聚合而不是继承。