在基本赋值中存储派生然后调用基本函数
Store derived in base assignement then call base function
我来自 Java,对 C++ 有点陌生。
在 Java 中,我可以这样做:link to code
我创建了一个抽象基 class Mother
,在同一基 class.
的 public 函数中使用了一个纯虚函数
我试过了:
class Mother {
private:
virtual void bar() = 0;
public:
void foo();
};
void Mother::foo() {
// ... some code
bar();
}
class Child0: public Mother {
private:
void bar();
};
void Child0::bar() {
std::cout << "Child0" << std::endl;
}
class Child1: public Mother {
private:
void bar();
};
void Child1::bar() {
std::cout << "Child1" << std::endl;
}
// main code
int main() {
Mother mother;
if(condition) {
Child0 child;
mother = child;
} else {
Child1 child;
mother = child;
}
mother.foo();
}
但是我得到一个编译器错误:
main.cpp:35:12: fatal error: variable type 'Mother' is an abstract class
Mother mother;
^
main.cpp:5:22: note: unimplemented pure virtual method 'bar' in 'Mother'
virtual void bar() = 0;
^
我错过了什么?
您错过了 object slicing 陷阱,并且还有未定义的行为:当您分配
mother = child;
child
将 "sliced" 降低到 mother
,并删除任何多态行为。
如果你想保留多态性,使用指针:
Mother *mother;
if(condition) {
mother = new Child0;
} else {
mother = new Child1;
}
mother->foo();
delete mother;
确保 Mother
有一个虚拟析构函数。
请注意,您不能再使用内部作用域中的对象,因为一旦作用域结束,指针就会失效:
// Do not do this!
Mother *mother;
if(condition) {
Child0 child;
mother = &child;
}
mother->foo(); // <<<=== This is undefined behavior
C++ 与 Java 不同,它具有值语义并且没有隐式指针:当您声明 Mother mother;
时,您将获得 Mother
的实际实例。不多也不少。除了你的情况,其中 Mother
是抽象的:你 不能 有一个 Mother
!
的实例
稍后执行 mother = child;
只是将 child 的 Mother
部分分配给 mother
。这称为 "object slicing",因为您希望复制的 child 部分也被切掉了。
要解决此问题,您需要使用指针或引用,它们都可以引用动态类型不同于静态类型的 object(例如,Mother
实际上是Child0
)。我将使用最简单的拥有指针,std::unique_ptr
:
int main() {
std::unique_ptr<Mother> mother;
if(condition) {
mother = std::make_unique<Child0>();
} else {
mother = std::make_unique<Child1>();
}
// At this point, *mother is of static type Mother,
// but of dynamic type Child0 or Child1.
mother->foo();
}
请注意,我也已切换到动态分配:您的两个 children 实例是自动变量,这意味着它们会在其范围 {}
结束时死亡。 std::make_unique
构造一个具有动态生命周期的 object:它只会在持有它的 unique_ptr
死亡时死亡。
如另一个答案所述,由于您的 child object 将通过 Mother
的类型以多态方式被破坏,Mother
的析构函数应该是 virtual
正确发送。
class Mother {
// ...
public:
virtual ~Mother() = default;
};
我来自 Java,对 C++ 有点陌生。 在 Java 中,我可以这样做:link to code
我创建了一个抽象基 class Mother
,在同一基 class.
我试过了:
class Mother {
private:
virtual void bar() = 0;
public:
void foo();
};
void Mother::foo() {
// ... some code
bar();
}
class Child0: public Mother {
private:
void bar();
};
void Child0::bar() {
std::cout << "Child0" << std::endl;
}
class Child1: public Mother {
private:
void bar();
};
void Child1::bar() {
std::cout << "Child1" << std::endl;
}
// main code
int main() {
Mother mother;
if(condition) {
Child0 child;
mother = child;
} else {
Child1 child;
mother = child;
}
mother.foo();
}
但是我得到一个编译器错误:
main.cpp:35:12: fatal error: variable type 'Mother' is an abstract class
Mother mother;
^
main.cpp:5:22: note: unimplemented pure virtual method 'bar' in 'Mother'
virtual void bar() = 0;
^
我错过了什么?
您错过了 object slicing 陷阱,并且还有未定义的行为:当您分配
mother = child;
child
将 "sliced" 降低到 mother
,并删除任何多态行为。
如果你想保留多态性,使用指针:
Mother *mother;
if(condition) {
mother = new Child0;
} else {
mother = new Child1;
}
mother->foo();
delete mother;
确保 Mother
有一个虚拟析构函数。
请注意,您不能再使用内部作用域中的对象,因为一旦作用域结束,指针就会失效:
// Do not do this!
Mother *mother;
if(condition) {
Child0 child;
mother = &child;
}
mother->foo(); // <<<=== This is undefined behavior
C++ 与 Java 不同,它具有值语义并且没有隐式指针:当您声明 Mother mother;
时,您将获得 Mother
的实际实例。不多也不少。除了你的情况,其中 Mother
是抽象的:你 不能 有一个 Mother
!
的实例
稍后执行 mother = child;
只是将 child 的 Mother
部分分配给 mother
。这称为 "object slicing",因为您希望复制的 child 部分也被切掉了。
要解决此问题,您需要使用指针或引用,它们都可以引用动态类型不同于静态类型的 object(例如,Mother
实际上是Child0
)。我将使用最简单的拥有指针,std::unique_ptr
:
int main() {
std::unique_ptr<Mother> mother;
if(condition) {
mother = std::make_unique<Child0>();
} else {
mother = std::make_unique<Child1>();
}
// At this point, *mother is of static type Mother,
// but of dynamic type Child0 or Child1.
mother->foo();
}
请注意,我也已切换到动态分配:您的两个 children 实例是自动变量,这意味着它们会在其范围 {}
结束时死亡。 std::make_unique
构造一个具有动态生命周期的 object:它只会在持有它的 unique_ptr
死亡时死亡。
如另一个答案所述,由于您的 child object 将通过 Mother
的类型以多态方式被破坏,Mother
的析构函数应该是 virtual
正确发送。
class Mother {
// ...
public:
virtual ~Mother() = default;
};