覆盖纯虚函数
Overriding pure virtual functions
我一直在试图弄清楚为什么在 QTCreator 中尝试构建此代码时出现错误。我发现了其他一些与此类似的帖子,但我认为我有类似但不同的问题。
在 main.cpp 中,我基本上有一些过滤器(一个带有纯虚函数的模板化结构),我正在为我创建 returns MyProducts 的向量。我给过滤器一个规范(一个带有纯虚函数的模板化结构)和一个 MyProduct 向量来搜索。
但我在构建过程中不断收到此错误消息。
/Users/marcokok/Qt-workspace/Open_Closed_Principle/main.cpp:112: error: allocating an object of abstract class type 'Specification<MyProduct>'
/Users/marcokok/Qt-workspace/Open_Closed_Principle/main.cpp:112:36: error: allocating an object of abstract class type 'Specification<MyProduct>'
AndSpecification<MyProduct> as(cs, ss);
^
/Users/marcokok/Qt-workspace/Open_Closed_Principle/main.cpp:29:18: note: unimplemented pure virtual method 'is_satisfied' in 'Specification'
virtual bool is_satisfied(T* item) = 0;
^
这是我的源代码
main.cpp
#include <iostream>
#include <vector>
using namespace std;
enum class ColorTable
{
red,
green,
blue
};
enum class SizeTable
{
small,
medium,
large
};
struct MyProduct
{
string name;
ColorTable color;
SizeTable size;
};
template <typename T> struct Specification
{
virtual bool is_satisfied(T* item) = 0;
};
template <typename T> struct Filter
{
virtual vector<T*> filter(vector<T*> items, Specification<T>& spec) = 0;
};
struct BetterFilter : Filter<MyProduct>
{
vector<MyProduct*> filter(vector<MyProduct *> items, Specification<MyProduct> &spec) override
{
vector<MyProduct*> result;
for (auto& item : items)
{
if (spec.is_satisfied(item))
result.push_back(item);
}
return result;
}
};
struct ColorSpecification : Specification<MyProduct>
{
ColorTable color;
ColorSpecification(ColorTable color) : color(color)
{}
bool is_satisfied(MyProduct* item) override
{
if (item->color == color)
return true;
else
return false;
}
};
struct SizeSpecification : Specification<MyProduct>
{
SizeTable size;
SizeSpecification(SizeTable size) : size(size)
{}
bool is_satisfied(MyProduct* item) override
{
if (item->size == size)
return true;
else
return false;
}
};
template <typename T> struct AndSpecification : Specification<T>
{
Specification<T>& first;
Specification<T>& second;
AndSpecification(Specification<T> first, Specification<T> second) : first(first) , second(second)
{}
bool is_satisfied(T* item) override
{
if (first.is_satisfied(item) && second.is_satisfied(item))
return true;
else
return false;
}
};
int main()
{
MyProduct prod_1{"Apple", ColorTable::green, SizeTable::large};
MyProduct prod_2{"Jeans", ColorTable::green, SizeTable::small};
MyProduct prod_3{"Graphics Card", ColorTable::blue, SizeTable::large};
vector<MyProduct*> items = {&prod_1, &prod_2, &prod_3};
BetterFilter bf;
ColorSpecification cs(ColorTable::green);
SizeSpecification ss(SizeTable::large);
AndSpecification<MyProduct> as(cs, ss);
auto green_things = bf.filter(items, cs);
for (auto& item : green_things)
cout << item->name << " is green." << endl;
auto large_things = bf.filter(items, ss);
for (auto& item : large_things)
cout << item->name << " is large.\n\n" << endl;
// auto large_green_things = bf.filter(items, as);
//for (auto& item : large_green_things)
// cout << item->name << " is large and green." << endl;
return 0;
}
我试图在 coliru 中重现 OP 问题。
这是我得到的:
main.cpp: In function 'int main()':
main.cpp:112:42: error: cannot allocate an object of abstract type 'Specification<MyProduct>'
112 | AndSpecification<MyProduct> as(cs, ss);
| ^
main.cpp:27:30: note: because the following virtual functions are pure within 'Specification<MyProduct>':
27 | template <typename T> struct Specification
| ^~~~~~~~~~~~~
main.cpp:29:18: note: 'bool Specification<T>::is_satisfied(T*) [with T = MyProduct]'
29 | virtual bool is_satisfied(T* item) = 0;
| ^~~~~~~~~~~~
main.cpp:112:33: warning: unused variable 'as' [-Wunused-variable]
112 | AndSpecification<MyProduct> as(cs, ss);
| ^~
我注意到的第一件事:struct AndSpecification
坏了:
template <typename T> struct AndSpecification : Specification<T>
{
Specification<T>& first;
Specification<T>& second;
AndSpecification(Specification<T> first, Specification<T> second) : first(first) , second(second)
{}
};
成员变量 first
和 second
存储一个引用。但是,构造函数中的初始化是使用值参数完成的。 IE。成员用局部变量初始化,局部变量在构造函数离开后销毁(实际上,如果调用构造函数的完整表达式完成)。
关于override
,我没有头绪,所以我先解决了这个问题。
…并得到(令我惊讶的)以下输出:
Apple is green.
Jeans is green.
Apple is large.
Graphics Card is large.
我得出的结论是 found/fixed 错误和错误消息是相关的 ,但我仍然无法解释这一点。我手头最好的:如果代码包含 U.B. 则无法对结果做出任何期望。
在的帮助下,我找到了错误的原因:
值参数导致调用中的临时副本。这些副本属于 Specification<T>
类型,但该类型是抽象的,无法实例化。
您的编译器会告诉您错误发生的位置。
/Users/marcokok/Qt-workspace/Open_Closed_Principle/main.cpp:112:36: error: allocating an object of abstract class type 'Specification<MyProduct>'
AndSpecification<MyProduct> as(cs, ss);
^
实例化 Specification<MyProduct>
的尝试发生在使用 cs
作为 AndSpecification<MyProduct>
构造函数的第一个参数时。创建 cs
很好,但是这个函数调用以某种方式触发了抽象 class 的构造。那么让我们看看那个构造函数的声明。
AndSpecification(Specification<T> first, Specification<T> second)
第一个参数按值传递(与许多其他参数不同)。这意味着一个新构造的 Specification<MyProduct>
对象是从 cs
初始化的。 (查看 cs
的 Specification<MyProduct>
子对象,并将那些数据成员复制到新对象。)但是,Specification<MyProduct>
是抽象的(所有 Specification<T>
classes),所以无法构造。因此错误。
更改您的构造函数以通过引用接受参数。
AndSpecification(Specification<T>& first, Specification<T>& second)
// ^ ^
看到了吗?如果您知道如何阅读错误消息,它并不像您说的那么复杂。
我一直在试图弄清楚为什么在 QTCreator 中尝试构建此代码时出现错误。我发现了其他一些与此类似的帖子,但我认为我有类似但不同的问题。
在 main.cpp 中,我基本上有一些过滤器(一个带有纯虚函数的模板化结构),我正在为我创建 returns MyProducts 的向量。我给过滤器一个规范(一个带有纯虚函数的模板化结构)和一个 MyProduct 向量来搜索。
但我在构建过程中不断收到此错误消息。
/Users/marcokok/Qt-workspace/Open_Closed_Principle/main.cpp:112: error: allocating an object of abstract class type 'Specification<MyProduct>'
/Users/marcokok/Qt-workspace/Open_Closed_Principle/main.cpp:112:36: error: allocating an object of abstract class type 'Specification<MyProduct>'
AndSpecification<MyProduct> as(cs, ss);
^
/Users/marcokok/Qt-workspace/Open_Closed_Principle/main.cpp:29:18: note: unimplemented pure virtual method 'is_satisfied' in 'Specification'
virtual bool is_satisfied(T* item) = 0;
^
这是我的源代码
main.cpp
#include <iostream>
#include <vector>
using namespace std;
enum class ColorTable
{
red,
green,
blue
};
enum class SizeTable
{
small,
medium,
large
};
struct MyProduct
{
string name;
ColorTable color;
SizeTable size;
};
template <typename T> struct Specification
{
virtual bool is_satisfied(T* item) = 0;
};
template <typename T> struct Filter
{
virtual vector<T*> filter(vector<T*> items, Specification<T>& spec) = 0;
};
struct BetterFilter : Filter<MyProduct>
{
vector<MyProduct*> filter(vector<MyProduct *> items, Specification<MyProduct> &spec) override
{
vector<MyProduct*> result;
for (auto& item : items)
{
if (spec.is_satisfied(item))
result.push_back(item);
}
return result;
}
};
struct ColorSpecification : Specification<MyProduct>
{
ColorTable color;
ColorSpecification(ColorTable color) : color(color)
{}
bool is_satisfied(MyProduct* item) override
{
if (item->color == color)
return true;
else
return false;
}
};
struct SizeSpecification : Specification<MyProduct>
{
SizeTable size;
SizeSpecification(SizeTable size) : size(size)
{}
bool is_satisfied(MyProduct* item) override
{
if (item->size == size)
return true;
else
return false;
}
};
template <typename T> struct AndSpecification : Specification<T>
{
Specification<T>& first;
Specification<T>& second;
AndSpecification(Specification<T> first, Specification<T> second) : first(first) , second(second)
{}
bool is_satisfied(T* item) override
{
if (first.is_satisfied(item) && second.is_satisfied(item))
return true;
else
return false;
}
};
int main()
{
MyProduct prod_1{"Apple", ColorTable::green, SizeTable::large};
MyProduct prod_2{"Jeans", ColorTable::green, SizeTable::small};
MyProduct prod_3{"Graphics Card", ColorTable::blue, SizeTable::large};
vector<MyProduct*> items = {&prod_1, &prod_2, &prod_3};
BetterFilter bf;
ColorSpecification cs(ColorTable::green);
SizeSpecification ss(SizeTable::large);
AndSpecification<MyProduct> as(cs, ss);
auto green_things = bf.filter(items, cs);
for (auto& item : green_things)
cout << item->name << " is green." << endl;
auto large_things = bf.filter(items, ss);
for (auto& item : large_things)
cout << item->name << " is large.\n\n" << endl;
// auto large_green_things = bf.filter(items, as);
//for (auto& item : large_green_things)
// cout << item->name << " is large and green." << endl;
return 0;
}
我试图在 coliru 中重现 OP 问题。
这是我得到的:
main.cpp: In function 'int main()':
main.cpp:112:42: error: cannot allocate an object of abstract type 'Specification<MyProduct>'
112 | AndSpecification<MyProduct> as(cs, ss);
| ^
main.cpp:27:30: note: because the following virtual functions are pure within 'Specification<MyProduct>':
27 | template <typename T> struct Specification
| ^~~~~~~~~~~~~
main.cpp:29:18: note: 'bool Specification<T>::is_satisfied(T*) [with T = MyProduct]'
29 | virtual bool is_satisfied(T* item) = 0;
| ^~~~~~~~~~~~
main.cpp:112:33: warning: unused variable 'as' [-Wunused-variable]
112 | AndSpecification<MyProduct> as(cs, ss);
| ^~
我注意到的第一件事:struct AndSpecification
坏了:
template <typename T> struct AndSpecification : Specification<T>
{
Specification<T>& first;
Specification<T>& second;
AndSpecification(Specification<T> first, Specification<T> second) : first(first) , second(second)
{}
};
成员变量 first
和 second
存储一个引用。但是,构造函数中的初始化是使用值参数完成的。 IE。成员用局部变量初始化,局部变量在构造函数离开后销毁(实际上,如果调用构造函数的完整表达式完成)。
关于override
,我没有头绪,所以我先解决了这个问题。
…并得到(令我惊讶的)以下输出:
Apple is green.
Jeans is green.
Apple is large.
Graphics Card is large.
我得出的结论是 found/fixed 错误和错误消息是相关的 ,但我仍然无法解释这一点。我手头最好的:如果代码包含 U.B. 则无法对结果做出任何期望。
在
值参数导致调用中的临时副本。这些副本属于 Specification<T>
类型,但该类型是抽象的,无法实例化。
您的编译器会告诉您错误发生的位置。
/Users/marcokok/Qt-workspace/Open_Closed_Principle/main.cpp:112:36: error: allocating an object of abstract class type 'Specification<MyProduct>' AndSpecification<MyProduct> as(cs, ss); ^
实例化 Specification<MyProduct>
的尝试发生在使用 cs
作为 AndSpecification<MyProduct>
构造函数的第一个参数时。创建 cs
很好,但是这个函数调用以某种方式触发了抽象 class 的构造。那么让我们看看那个构造函数的声明。
AndSpecification(Specification<T> first, Specification<T> second)
第一个参数按值传递(与许多其他参数不同)。这意味着一个新构造的 Specification<MyProduct>
对象是从 cs
初始化的。 (查看 cs
的 Specification<MyProduct>
子对象,并将那些数据成员复制到新对象。)但是,Specification<MyProduct>
是抽象的(所有 Specification<T>
classes),所以无法构造。因此错误。
更改您的构造函数以通过引用接受参数。
AndSpecification(Specification<T>& first, Specification<T>& second)
// ^ ^
看到了吗?如果您知道如何阅读错误消息,它并不像您说的那么复杂。