我们可以在 C++ 类中编写抽象关键字吗?
12 回答
#define abstract
不。
在 C++ 中,纯虚函数声明为:
class X
{
public:
virtual void foo() = 0;
};
任何至少包含其中一个的类都被认为是抽象的。
不,C++ 没有关键字 abstract。但是,您可以编写纯虚函数;这就是表达抽象类的 C++ 方式。
它是作为 .NET 框架的 C++/CLI 语言规范的一部分引入的关键字。
不,你需要在一个类中至少有一个纯虚函数是抽象的。
这是一个很好的参考cplusplus.com
正如其他人指出的那样,如果添加纯虚函数,则该类将变为抽象。
但是,如果您想实现一个没有纯虚拟成员的抽象基类,我发现使构造函数受保护很有用。这样,您强制用户继承 ABC 以使用它。
例子:
class Base
{
protected:
Base()
{
}
public:
void foo()
{
}
void bar()
{
}
};
class Child : public Base
{
public:
Child()
{
}
};
实际上关键字abstract
存在于 C++(至少是 VS2010)中,我发现它可用于将类/结构声明为非实例化。
struct X abstract {
static int a;
static void foX(){};
};
int X::a = 0;
struct Y abstract : X { // something static
};
struct Z : X { // regular class
};
int main() {
X::foX();
Z Zobj;
X Xobj; // error C3622
}
MSDN:https ://msdn.microsoft.com/en-us/library/b0z6b513%28v=vs.110%29.aspx
不,您不能使用 abstract 作为关键字,因为 C++ 中没有这样的关键字可用。
如果要将 C++ 类声明为抽象类,则可以将至少一个函数声明为纯虚函数。
但是在派生类中,您必须提供定义,否则会出现编译错误。
例子:
class A
{
public:
virtual void sum () = 0;
};
笔记:
你可以使用 abstract 作为变量名、类名,因为正如我告诉你的,abstract 不是 C++ 中的关键字。
不,C++ 没有关键字 abstract。但是,您可以编写纯虚函数;这就是表达抽象类的 C++ 方式。它是作为 .NET 框架的 C++/CLI 语言规范的一部分引入的关键字。你需要在一个类中至少有一个纯虚函数是抽象的。
class SomeClass {
public:
virtual void pure_virtual() = 0; // a pure virtual function
};
没有关键字“抽象”,但纯虚函数将一个类转换为抽象类,可以扩展和重新用作接口。
抽象关键字在java中呈现,类似的抽象我们可以在C++中使用纯虚函数来实现。
大多数 C++ 编译器没有abstract
关键字。
一个廉价的抽象关键字
尽管您可以像这样定义具有该名称的宏:
#define abstract
class foo abstract { ... };
它对类绝对没有影响,但是,如果任何变量、函数、任何东西被命名为“抽象”,那#define
都不会让你的代码快乐。
创建一个抽象类
正如其他人所提到的,您可以通过创建纯虚函数并将其设置为0
这样来强制类抽象:
class foo
{
virtual void func() = 0;
};
foo::func() { /* some default code [not required] */ }
优点:因为即使是纯虚函数也可以有主体,即使定义为抽象(纯虚)的函数已定义,您也可以将类抽象化。但是,与其他虚函数相反,纯虚函数不需要有实体。
缺点:您被迫创建至少一个纯虚函数,并迫使所有派生类定义该函数,而不是被视为抽象函数。如果你反正有这样的功能,那就太好了!但通常情况并非如此。
正确的方法
实际上有一种巧妙的方法可以创建一个鲜为人知的抽象类。你仍然需要创建一个纯虚函数……事实上析构函数可以是一个纯虚函数!使用关键字的类中总是有一个析构函数virtual
,所以这里没有犹豫。
class foo {
virtual ~foo() = 0;
};
foo * f(new foo); // this fails, foo is abstract
从 foo 派生的类现在必须声明一个显式析构函数(较新的编译器正确地隐式创建一个,但它仍然是一个纯虚函数),它不是像这样的纯虚函数:
class bar : public foo {
virtual ~bar() override {}
};
请注意,我们没有abstract
关键字,但我们确实有一个override
关键字,它非常有用,因此当函数签名更改时,您无法编译,直到从您的基类派生的所有类都相应地更新了它们的虚函数。
默认析构函数的效果
使用析构函数作为纯虚函数的一个有趣的方面是派生类会自动获得一个析构函数(如果你没有定义一个),这意味着你的派生类是自动非抽象的(假设只有析构函数是纯虚函数)基类)。
换句话说,您可以声明bar
:
class bar : public foo {
void some_function();
};
它自动不是抽象的,因为默认析构函数不是抽象的,因为它或多或少看起来像这样:
virtual ~bar() override {}
如果你不自己定义。
换句话说,如果你想定义另一个仍然是抽象的层(即如果你想new bar
编译失败),那么你必须声明你自己的析构函数并将其标记为纯虚拟:
class bar : public foo {
virtual ~bar() override = 0;
void some_function();
};
bar::~bar() {}
({}
and= 0
不能一起使用,所以你必须单独声明析构函数体。)