I'm trying to use an abstract class when passing an extended object as an parameter to a function, but my attempts so far have led to some compiler errors.
在将扩展对象作为参数传递给函数时,我尝试使用一个抽象类,但到目前为止,我的尝试导致了一些编译器错误。
I have a few clues as to what the problem is, I'm obviously not allowed to instantiate an abstract class, and I believe some of the code in MyClass is trying to do this, even though this is not my intention. Some researching has suggested that I should reference the object as a pointer to achieve what I want, but my attempts so far have failed and I'm not even sure that this is the answer (hence my asking here).
我有一些关于问题的线索,很明显,我不允许实例化一个抽象类,而且我相信MyClass中的一些代码正在尝试这样做,尽管这不是我的意图。一些研究表明,我应该把对象作为一个指针来实现我想要的东西,但是到目前为止我的尝试都失败了,我甚至不确定这就是答案(因此我在这里问)。
I'll submit now that I'm more familiar with Java than C++, and I'm sure part of my problem is due to this.
现在我将提交,我对Java比c++更熟悉,而且我确信我的部分问题是由于这个原因。
Here is an example of what I'm trying to do in my program:
下面是我在我的计划中要做的一个例子:
class A {
public:
virtual void action() = 0;
};
class B : public A {
public:
B() {}
void action() {
// Do stuff
}
};
class MyClass {
public:
void setInstance(A newInstance) {
instance = newInstance;
}
void doSomething() {
instance.action();
}
private:
A instance;
};
int main(int argc, char** argv) {
MyClass c;
B myInstance;
c.setInstance(myInstance);
c.doSomething();
return 0;
}
This example produces the same compiler error that I am getting in my program:
这个例子产生了我在程序中得到的相同的编译错误:
sean@SEAN-PC:~/Desktop$ gcc -o test test.cpp
test.cpp:20: error: cannot declare parameter ‘newInstance’ to be of abstract type ‘A’
test.cpp:2: note: because the following virtual functions are pure within ‘A’:
test.cpp:4: note: virtual void A::action()
test.cpp:30: error: cannot declare field ‘MyClass::instance’ to be of abstract type ‘A’
test.cpp:2: note: since type ‘A’ has pure virtual functions
test.cpp: In function ‘int main(int, char**)’:
test.cpp:36: error: cannot allocate an object of abstract type ‘A’
test.cpp:2: note: since type ‘A’ has pure virtual functions
Update
Thanks for the feedback everyone.
谢谢大家的反馈。
I've since changed "MyClass::instance to contain a pointer of type A, but I now get some bizarre errors related to the vtable:
我已经更改了“MyClass::instance,以包含a类型的指针,但现在我得到了一些与vtable相关的奇怪错误:
sean@SEAN-PC:~/Desktop$ gcc -o test test.cpp
/tmp/ccoEdRxq.o:(.rodata._ZTI1B[typeinfo for B]+0x0): undefined reference to `vtable for __cxxabiv1::__si_class_type_info'
/tmp/ccoEdRxq.o:(.rodata._ZTI1A[typeinfo for A]+0x0): undefined reference to `vtable for __cxxabiv1::__class_type_info'
/tmp/ccoEdRxq.o:(.rodata._ZTV1A[vtable for A]+0x8): undefined reference to `__cxa_pure_virtual'
collect2: ld returned 1 exit status
My modified code is as follows (A and B have not been modified):
我修改后的代码如下(A和B未修改):
class MyClass {
public:
void setInstance(A* newInstance) {
instance = newInstance;
}
void doSomething() {
instance->action();
}
private:
A* instance;
};
int main(int argc, char** argv) {
MyClass c;
B myInstance;
c.setInstance(&myInstance);
c.doSomething();
return 0;
}
11 个解决方案
#1
27
Your problem is that you should accept a reference in your function. The reason is that a reference does not actually copy the argument passed. If you however accept an A
- instead of a reference A&
- then you actually copy the argument passed into the parameter object, and what you get is an object of type A
- but which is actually not allowed!
你的问题是你应该在你的函数中接受一个引用。原因是引用实际上并没有复制经过的参数。如果您接受一个A而不是引用A& -那么您实际上复制传入参数对象的参数,您得到的是A类型的对象,但实际上是不允许的!
// the reference parameter will reference the actual argument
void setInstance(A &newInstance) {
// assign the address of the argument to the pointer member
// instance.
instance = &newInstance;
}
And then you will have to change the member in your class to be a pointer. It can't be a reference because setInstance
will change what it references - a reference can only reference one object during its entire lifetime, while a pointer can be set to point do different things just by reassigning it a different address. The remaining parts look like this then
然后你需要将你的类中的成员变成一个指针。它不能作为引用,因为setInstance将更改它引用的内容——引用只能在其整个生命周期中引用一个对象,而指针可以通过重新分配一个不同的地址来设置不同的内容。剩下的部分是这样的。
void doSomething() {
// call a member function on the object pointed to
// by instance!
instance->action();
}
private:
// a pointer to some object derived from A
A *instance;
Also note that you have to compile C++ programs using g++
, because it additionally links the C++ standard library to your code
还要注意,您必须使用g++编译c++程序,因为它还将c++标准库链接到您的代码中。
g++ -o test test.cpp # instead of gcc!
#2
5
What you are doing would work in Java because declaring a parameter or member variable of type "A" really means a "pointer to an A". In C++, you actually need to be explicit about that since they are two different things:
您所做的将在Java中发挥作用,因为声明类型“a”的参数或成员变量实际上意味着“指向a的指针”。在c++中,你需要明确说明,因为它们是两个不同的东西:
void setInstance(A* newInstance) { // pointer to an "A"
instance = newInstance;
}
And in the declaration:
和声明:
A* instance; // Not an actual "A", but a pointer to an "A"
#3
3
Your problem now is a linkage. For C++ program, standard C++ library has to be added:
你现在的问题是联系。对于c++程序,必须添加标准c++库:
gcc -o test -lstdc++ test.cpp
测试-lstdc++ test.cpp。
#4
3
I believe this is what you're trying to do. It demonstrates the polymorphism by actually printing something out depending on whether the handle class points to an instance of B or C. Others are correct that you would probably also want a virtual destructor.
我相信这就是你想要做的。它通过实际打印出一些东西来显示多态,这取决于处理类是否指向B或c的实例,其他的是正确的,您可能还需要一个虚拟析构函数。
This compiles with: g++ test.cpp -o Test
此编译为:g++测试。cpp - o测试
#include <stdio.h>
class A {
public:
virtual void action() = 0;
};
class B : public A {
public:
B() {}
void action() {
printf("Hello World\n");
}
};
class C : public A {
public:
C() {}
void action() {
printf("Goodbye World\n");
}
};
class AHandleClass {
public:
void setInstance(A *A_Instance) {
APointer = A_Instance;
}
void doSomething() {
APointer->action();
}
private:
A *APointer;
};
int main(int argc, char** argv) {
AHandleClass AHandle;
B BInstance;
C CInstance;
AHandle.setInstance(&BInstance);
AHandle.doSomething();
AHandle.setInstance(&CInstance);
AHandle.doSomething();
return 0;
}
#5
1
You should store A as a pointer.
您应该将A存储为指针。
A* instance;
Edit: I've written "reference" before. There is a difference in C++.
编辑:我以前写过“参考”。在c++中有一个区别。
#6
1
You don't have to use pointers if you resign of the setter and use a constructor. It's one of the important features in C++: base initializers in constructors often allow to avoid using pointers.
如果您放弃setter并使用构造函数,就不必使用指针。它是c++中的一个重要特性:构造函数中的基础初始化器通常允许避免使用指针。
class MyClass {
public:
MyClass(A & newInstance) : instance(newInstance) {
}
void doSomething() {
instance.action();
}
private:
A & instance;
};
int main(int argc, char** argv) {
B myInstance;
MyClass c(myInstance);
#7
1
I had this problem by including parent.h
before iostream
:
我有个问题,包括父母。h iostream之前:
wrong:
错误的:
include "parent.h"
include <iostream>
right:
正确的:
include <iostream>
include "parent.h"
#8
1
Johannes Schaub - litb is correct.
Johannes Schaub - litb是正确的。
In C++, Abstract class can't be used as functions' param or return type. We can't instantiate an abstract object.
在c++中,抽象类不能用作函数的param或返回类型。我们不能实例化一个抽象对象。
So need to use & or *.
所以需要使用&或*。
#9
0
You must use a pointer to A as a member of MyClass.
您必须使用一个指针作为MyClass的成员。
class MyClass {
public:
void setInstance(A *newInstance) {
instance = newInstance;
}
void doSomething() {
instance->action();
}
private:
A *instance;
};
if you do not do that, MyClass constructor will try to instantiate an A object (as it would for any member object), which is not possible since A is abstract.
如果您不这样做,MyClass构造函数将尝试实例化一个对象(就像任何成员对象一样),这是不可能的,因为A是抽象的。
#10
0
When you say
当你说
A instance;
you will create a new object of type A. But you have already said that A isa an abstract class, so you can't to that. You need to use a pointer, as several otherrs have indicated, or make A non-abstract.
您将创建a类型的新对象,但是您已经说过,isa是一个抽象类,所以您不能这样做。您需要使用一个指针,就像其他几个人指出的那样,或者做一个非抽象的。
#11
0
Dmitry is correct, you should use -lstdc++ if you use gcc, but even better is to use g++
instead. (Same syntax).
Also, you would note (I guess if you add -Wall) that you get a warning that your class with virtual functions is without a destructor, so a good idea is to add a (virtual) destructor to A as well.
Dmitry是正确的,如果您使用gcc,您应该使用-lstdc++,但是最好是使用g++。(语法)。同样,您会注意到(我猜如果您添加了-Wall),您会得到一个警告,您的类具有虚拟函数没有析构函数,所以一个好主意是向a添加一个(虚拟)析构函数。
#1
27
Your problem is that you should accept a reference in your function. The reason is that a reference does not actually copy the argument passed. If you however accept an A
- instead of a reference A&
- then you actually copy the argument passed into the parameter object, and what you get is an object of type A
- but which is actually not allowed!
你的问题是你应该在你的函数中接受一个引用。原因是引用实际上并没有复制经过的参数。如果您接受一个A而不是引用A& -那么您实际上复制传入参数对象的参数,您得到的是A类型的对象,但实际上是不允许的!
// the reference parameter will reference the actual argument
void setInstance(A &newInstance) {
// assign the address of the argument to the pointer member
// instance.
instance = &newInstance;
}
And then you will have to change the member in your class to be a pointer. It can't be a reference because setInstance
will change what it references - a reference can only reference one object during its entire lifetime, while a pointer can be set to point do different things just by reassigning it a different address. The remaining parts look like this then
然后你需要将你的类中的成员变成一个指针。它不能作为引用,因为setInstance将更改它引用的内容——引用只能在其整个生命周期中引用一个对象,而指针可以通过重新分配一个不同的地址来设置不同的内容。剩下的部分是这样的。
void doSomething() {
// call a member function on the object pointed to
// by instance!
instance->action();
}
private:
// a pointer to some object derived from A
A *instance;
Also note that you have to compile C++ programs using g++
, because it additionally links the C++ standard library to your code
还要注意,您必须使用g++编译c++程序,因为它还将c++标准库链接到您的代码中。
g++ -o test test.cpp # instead of gcc!
#2
5
What you are doing would work in Java because declaring a parameter or member variable of type "A" really means a "pointer to an A". In C++, you actually need to be explicit about that since they are two different things:
您所做的将在Java中发挥作用,因为声明类型“a”的参数或成员变量实际上意味着“指向a的指针”。在c++中,你需要明确说明,因为它们是两个不同的东西:
void setInstance(A* newInstance) { // pointer to an "A"
instance = newInstance;
}
And in the declaration:
和声明:
A* instance; // Not an actual "A", but a pointer to an "A"
#3
3
Your problem now is a linkage. For C++ program, standard C++ library has to be added:
你现在的问题是联系。对于c++程序,必须添加标准c++库:
gcc -o test -lstdc++ test.cpp
测试-lstdc++ test.cpp。
#4
3
I believe this is what you're trying to do. It demonstrates the polymorphism by actually printing something out depending on whether the handle class points to an instance of B or C. Others are correct that you would probably also want a virtual destructor.
我相信这就是你想要做的。它通过实际打印出一些东西来显示多态,这取决于处理类是否指向B或c的实例,其他的是正确的,您可能还需要一个虚拟析构函数。
This compiles with: g++ test.cpp -o Test
此编译为:g++测试。cpp - o测试
#include <stdio.h>
class A {
public:
virtual void action() = 0;
};
class B : public A {
public:
B() {}
void action() {
printf("Hello World\n");
}
};
class C : public A {
public:
C() {}
void action() {
printf("Goodbye World\n");
}
};
class AHandleClass {
public:
void setInstance(A *A_Instance) {
APointer = A_Instance;
}
void doSomething() {
APointer->action();
}
private:
A *APointer;
};
int main(int argc, char** argv) {
AHandleClass AHandle;
B BInstance;
C CInstance;
AHandle.setInstance(&BInstance);
AHandle.doSomething();
AHandle.setInstance(&CInstance);
AHandle.doSomething();
return 0;
}
#5
1
You should store A as a pointer.
您应该将A存储为指针。
A* instance;
Edit: I've written "reference" before. There is a difference in C++.
编辑:我以前写过“参考”。在c++中有一个区别。
#6
1
You don't have to use pointers if you resign of the setter and use a constructor. It's one of the important features in C++: base initializers in constructors often allow to avoid using pointers.
如果您放弃setter并使用构造函数,就不必使用指针。它是c++中的一个重要特性:构造函数中的基础初始化器通常允许避免使用指针。
class MyClass {
public:
MyClass(A & newInstance) : instance(newInstance) {
}
void doSomething() {
instance.action();
}
private:
A & instance;
};
int main(int argc, char** argv) {
B myInstance;
MyClass c(myInstance);
#7
1
I had this problem by including parent.h
before iostream
:
我有个问题,包括父母。h iostream之前:
wrong:
错误的:
include "parent.h"
include <iostream>
right:
正确的:
include <iostream>
include "parent.h"
#8
1
Johannes Schaub - litb is correct.
Johannes Schaub - litb是正确的。
In C++, Abstract class can't be used as functions' param or return type. We can't instantiate an abstract object.
在c++中,抽象类不能用作函数的param或返回类型。我们不能实例化一个抽象对象。
So need to use & or *.
所以需要使用&或*。
#9
0
You must use a pointer to A as a member of MyClass.
您必须使用一个指针作为MyClass的成员。
class MyClass {
public:
void setInstance(A *newInstance) {
instance = newInstance;
}
void doSomething() {
instance->action();
}
private:
A *instance;
};
if you do not do that, MyClass constructor will try to instantiate an A object (as it would for any member object), which is not possible since A is abstract.
如果您不这样做,MyClass构造函数将尝试实例化一个对象(就像任何成员对象一样),这是不可能的,因为A是抽象的。
#10
0
When you say
当你说
A instance;
you will create a new object of type A. But you have already said that A isa an abstract class, so you can't to that. You need to use a pointer, as several otherrs have indicated, or make A non-abstract.
您将创建a类型的新对象,但是您已经说过,isa是一个抽象类,所以您不能这样做。您需要使用一个指针,就像其他几个人指出的那样,或者做一个非抽象的。
#11
0
Dmitry is correct, you should use -lstdc++ if you use gcc, but even better is to use g++
instead. (Same syntax).
Also, you would note (I guess if you add -Wall) that you get a warning that your class with virtual functions is without a destructor, so a good idea is to add a (virtual) destructor to A as well.
Dmitry是正确的,如果您使用gcc,您应该使用-lstdc++,但是最好是使用g++。(语法)。同样,您会注意到(我猜如果您添加了-Wall),您会得到一个警告,您的类具有虚拟函数没有析构函数,所以一个好主意是向a添加一个(虚拟)析构函数。