我的基类Car包含engine无法在基类中初始化的字段.我只能在子类中初始化它,例如ElectricCar我可以编写engine = new ElectricEngine.但是我在基类中使用了字段.所以我有一个使用但未初始化的字段:
public class Car {
protected Engine engine;
public void Start() {
engine.Start();
// do something else
}
public void Stop {
engine.Stop();
// do something else
}
public void Diagnose() {
engine.Diagnose();
// anotherField.Diagnose();
// oneAnotherField.Diagnose();
}
}
Run Code Online (Sandbox Code Playgroud)
如何更好地初始化引擎?
版本1.字段保证初始化但有许多字段构造函数看起来很难看.没有错误,但很难看.
public class Car {
protected Engine engine;
public Car(Engine engine) {
this.engine = engine;
}
public void Start() {
engine.Start();
// do something else
}
public void Stop …Run Code Online (Sandbox Code Playgroud) 我正在阅读有效的C++,并且有"第9项:在构造或销毁期间从不调用虚函数".而且我想知道我的代码是否正常,即使它违反了这个规则:
using namespace std;
class A{
public:
A(bool doLog){
if(doLog)
log();
}
virtual void log(){
cout << "logging A\n";
}
};
class B: public A{
public:
B(bool doLog) : A(false){
if(doLog)
log();
}
virtual void log(){
cout << "logging B\n";
}
};
int main() {
A a(true);
B b(true);
}
Run Code Online (Sandbox Code Playgroud)
这种方法有问题吗?当我做一些更复杂的事情时,我可能遇到麻烦吗?
它接近我,大多数答案都没有得到我在那里做的,他们只是再次解释为什么从构造函数调用虚函数可能有危险.
我想强调一下我的程序输出如下:
logging A
logging B
Run Code Online (Sandbox Code Playgroud)
因此,我在构造时记录A并在构造时记录B.这就是我想要的!但我问你是否发现任何错误(有潜在危险)与我的"黑客"克服在构造函数中调用虚函数的问题.
可能的重复:
在构造函数内调用虚函数
我有一个 Shape 类及其子类 Sphere :
//Shape :
class Shape
{
public:
Shape(const string& name);
virtual ~Shape();
virtual string getName();
protected:
string mName;
};
Shape::Shape(const string& name) : mName(name)
{
/*Some stuff proper to Shape*/
/*Some stuff proper to subclass (sphere)*/
/*Some stuff proper to Shape*/
}
Shape::~Shape(){}
string Shape::getName(){ return mName; }
//Sphere :
class Sphere : public Shape
{
public:
Sphere(const string& name, const float radius);
virtual ~Sphere();
virtual string getRadius();
protected:
float mRadius;
}
Sphere::Sphere(const string& …Run Code Online (Sandbox Code Playgroud) 因此,基于粗略搜索,我已经知道从构造函数中调用虚函数(纯函数或其他函数)是不行的.我重新构建了我的代码,以确保我没有这样做.虽然这会导致我的类的用户在他们的代码中添加一个额外的函数调用,但这真的不是什么大不了的事.也就是说,它们不是在循环中调用构造函数,而是调用函数(事实上!)来提高代码的性能,因为我们没有每次构建和销毁相关对象的内务处理.
但是,我偶然发现了一些有趣的事情......
在抽象类中我有这样的东西:
// in AbstractClass.h:
class AbstractClass {
public:
AbstractClass() {}
virtual int Func(); //user can override
protected:
// Func broken up, derived class must define these
virtual int Step1() = 0;
virtual int Step2() = 0;
virtual int Step3() = 0;
// in AbstractClass.cpp:
int AbstractClass::Func() {
Step1();
// Error checking goes here
Step2();
// More error checking...
// etc...
}
Run Code Online (Sandbox Code Playgroud)
基本上,有一个共同的结构,纯虚函数大多数时间都遵循,但如果它们不是Func()是虚拟的,并允许派生类指定顺序.但是,每个步骤都必须在派生类中实现.
我只是想确保在Func()函数调用纯虚函数时,没有什么我在这里做错了.也就是说,使用基类,如果你调用StepX(),就会发生不好的事情.但是,通过创建派生对象然后在该派生对象上调用Func()(例如MyDerivedObject.Func();)来使用该类,该派生对象应该正确地重载所有纯虚函数.
通过这种方法,我有什么遗漏或做错了吗?谢谢您的帮助!
我有一个abstact基类,在它的构造函数中调用一个虚方法.在传递一个shared_ptr基类之后,找不到该方法的实现.
class a
{
public:
a() { fill(); }
protected:
virtual void fill() = 0;
}
class b : public a
{
public:
b() : a();
protected:
virtual void fill() { // do something }
}
....
shared_ptr<a> sptr = shared_ptr<a> ( new b()): // error happens here on runtime
Run Code Online (Sandbox Code Playgroud)
执行此操作时,我得到一个SIGABRT,因为它试图执行 virtual void fill() = 0;
请考虑以下代码:
#include <iostream>
using namespace std;
class A
{
public:
virtual void f() = 0;
A(){f();}
};
void A::f() {
cout<<"A"<<endl;
}
class B:public A{
public:
void f(){cout<<"B"<<endl;}
};
int main()
{
B b;
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我直接从构造函数中调用虚函数并获取编译器警告,其中显示:
warning:abstract virtual'virtual void A :: f()'从构造函数调用.
但它执行时没有终止并打印A.
如果我像这样包装函数的调用:
class A
{
public:
virtual void f() = 0;
A(){g();}
void g(){f();}
};
void A::f(){cout<<"A"<<endl;}
class B:public A{
public:
void f(){cout<<"B"<<endl;}
};
int main()
{
B b;
}
Run Code Online (Sandbox Code Playgroud)
编译器在编译期间不会输出任何警告,但会在运行时使用以下消息进行压缩:
pure virtual method called
terminate called without …Run Code Online (Sandbox Code Playgroud) 考虑以下2个程序.
#include <iostream>
using std::cout;
class Base {
public:
virtual void f()=0;
void g() {
f();
}
virtual ~Base() { }
};
class Derived : public Base
{
public:
void f() {
cout<<"Derived::f() is called\n";
}
~Derived() {}
};
class Derived1 : public Base
{
public:
void f() {
cout<<"Derived1::f() is called\n";
}
~Derived1() { }
};
int main() {
Derived1 d;
Base& b=d;
b.g();
b.f();
}
Run Code Online (Sandbox Code Playgroud)
编译并运行良好并给出预期的结果..
#include <iostream>
using std::cout;
class Base {
public:
virtual void f()=0;
Base() …Run Code Online (Sandbox Code Playgroud) 所以最近不小心从一个基类的构造函数中调用了一些虚函数,即Calling virtual functions inside constructors。
我意识到我不应该这样做,因为不会调用虚函数的覆盖,但是我怎样才能实现一些类似的功能?我的用例是我希望在构造对象时运行一个特定的函数,并且我不希望编写派生类的人不得不担心它在做什么(因为他们当然可以在它们的派生类构造函数)。但是,需要依次调用的函数恰好调用了一个虚函数,我希望派生类能够在需要时覆盖它。
但是因为调用了一个虚函数,我不能只是把这个函数粘在基类的构造函数中,让它以这种方式自动运行。所以我似乎被卡住了。
有没有其他方法可以实现我想要的?
编辑:我碰巧使用 CRTP 从基类访问派生类中的其他方法,我可以在构造函数中使用它而不是虚函数吗?或者是否存在同样的问题?我想如果被调用的函数是静态的,它也许可以工作?
编辑2:也刚刚发现这个类似的问题:构造后立即调用虚拟方法
我有一些代码,我真的想从构造函数调用一个虚方法.我知道这被认为是不安全的,我对对象构造了解得足以理解为什么.我也没有遇到这些问题.目前我的代码正在运行,我认为应该没问题,但我想确定一下.
这是我在做的事情:
我有一些类层次结构,并且有一个普通的公共函数,它像往常一样转发到私有虚方法.但是我确实希望在构造我的对象时调用这个公共方法,因为它将所有数据填充到对象中.我绝对肯定这个虚拟调用来自叶类,因为从类层次结构的任何其他部分使用这个虚方法根本就没有意义.
因此,在我看来,一旦我进行虚拟调用就应该完成对象创建,一切都应该没问题.还有什么可能出错吗?我想我必须用一些重要的注释来标记逻辑的这一部分,以解释为什么这个逻辑永远不会被移动到任何基本条目,即使看起来它可能被移动.但除了其他程序员的愚蠢之外我应该没事,不应该吗?
可能重复:
在构造函数内调用虚函数
看看这段代码.在Base类的构造函数中,我们可以使用'this'指针调用纯虚函数.现在,当我想创建一个指向同一个类的类型指针并将"this"转换为相同类型时.它抛出运行时异常'纯虚函数调用异常'.为什么会这样?
#include <iostream>
using namespace std;
class Base
{
private:
virtual void foo() = 0;
public:
Base()
{
//Uncomment below 2 lines and it doesn't work (run time exception)
//Base * bptr = (Base*)this;
//bptr->foo();
//This call works
this->foo();
}
};
void
Base::foo()
{
cout << "Base::foo()=0" << endl;
}
class Der : public Base
{
public:
Der()
{
}
public:
void foo()
{
cout << "Der::foo()" << endl;
}
};
int main()
{
cout << "Hello World!" …Run Code Online (Sandbox Code Playgroud) c++ ×9
constructor ×4
pure-virtual ×4
inheritance ×3
virtual ×2
c# ×1
compilation ×1
function ×1
oop ×1
shared-ptr ×1