如果只定义此方法,则会出现编译错误。
void classA::testMethod() {
}
因此必须首先声明:
class classA {
void testMethod();
};
为什么要宣布这些?
我知道对于常见的C方法方法,它不需要声明,但只能定义它们:
void test() {
}
答案 0 :(得分:8)
在定义方法之前,您不需要声明方法,但是您需要在类中声明类方法。否则它不会成为一种阶级方法。
这似乎是一个矛盾,但定义也是一个宣言。所以这意味着定义可能出现在类本身中:
class A {
void testMethod() { /*...*/ }
};
[编辑]
而且,实际上,在类声明中,有private
,protected
和public
部分。这是封装所必需的。如果你可以在类之外声明方法,那么你将失去封装。任何人都可以通过定义额外的getter和setter来访问私有成员,即使那些没有意义。类不变量将变得毫无意义。
答案 1 :(得分:7)
客观和主观有几个次要原因(即允许指定可见性,作为类的接口,可能还有几个与编译和链接阶段和TU符号可见性相关的其他原因,更不用说类是基本的封装单位,所有这些暗示)但毫无疑问的是标准规定:
N3797 - class.mfct / p2
可以在其类定义中定义成员函数(8.4) 在哪种情况下,它是内联成员函数(7.1.2),或者它可能是 如果已经定义,则在其类定义之外定义 声明但未在其类定义中定义。成员函数 出现在类定义之外的定义 在包含类定义的命名空间范围内。会员除外 出现在类定义之外的函数定义 除了类的成员函数的显式特化 模板和成员函数模板(14.7)出现在 类定义,成员函数不得重新声明。
强调我的。
答案 2 :(得分:6)
它有助于封装。如果你有A级
class A {
public:
foo();
bar();
}
您可以确定只有方法foo
和bar
混淆了该类的私有数据成员。 (或指针魔术或当然未定义的行为)
答案 3 :(得分:3)
所有以前的答案都是正确的,但是 他们没有指出规则背后的原因。在C ++中, 关闭类定义;你以后不能添加它。这个 非静态数据成员是必要的,因为他们确定 大小(和隐式生成的特殊函数),但是 它是C ++中所有类成员的基本原则:不仅仅是 数据,但功能,类型等。它被认为是必不可少的 良好的封装。
对于大多数(但不是全部)支持该语言的语言都是如此 阶级的概念。
这也解释了为什么情况有所不同 名称空间(未关闭)。
答案 4 :(得分:2)
"方法"或"会员功能" (这是C ++中比较常见的术语)是类声明的一部分。由于您必须在一个地方声明一个C ++类,因此您必须确保所有"成员函数" (或"方法")已存在于该声明中。
我知道对于常见的C方法方法,它不需要声明,但它们 可以定义
当你引用一种常见的C方法"在C ++中,你实际上是指"常用功能"。请注意,您可以在可以声明此类函数的任何位置声明类。
另请注意,您可以使用正文声明成员函数。您不必单独声明和定义。即这完全有效:
class A{
void privateMethod() {
// do something here...
}
public:
void publicMethod() {
// do something here...
}
};
答案 5 :(得分:2)
请注意使用限定符::
。这意味着
因此,编写void A::testMethod()
假定定义了一个类或命名空间A
- 这就是C ++的定义方式。这适用于
void A::testMethod();
以及
void A::testMethod()
{
}
另请注意全局命名空间,其中::
左侧确实没有任何内容,如
void ::testMethod()
{
}
根据定义,总是定义全局命名空间,因此上面的代码定义了一个类似于没有限定符的C风格的函数。
答案 6 :(得分:2)
即使标准未强制要求,也有以下两个原因需要在类定义中声明所有类方法。
您只能在类声明中声明某些内容为public,private或protected,但您无法在.cpp文件中的方法定义中执行此操作。那么你的独立课堂方法有什么可见性呢?
如果标准决定选择三者中的一个作为默认值(C ++默认为private),并将该可见性放在您的方法上,那么您现在遇到了一个范围问题。即使是最严格的可见性(私有)也意味着您可以在任何其他成员方法中使用该方法,包括源文件中之前定义的那些方法。如果没有类定义中的声明,那些早期的函数就不会知道你的独立方法,因此你违反了范围规则。
在你的foo.h标题中:
class foo
{
public:
foo() {}
virtual ~foo() {}
declaredMethod();
};
在你的foo.cpp
中foo::declaredMethod()
{
...
freeStandingMethod(); // This should be legal, but it can't work since we
// haven't seen foo::freeStandingMethod() yet
...
}
foo::freeStandingMethod()
{
...
}
即使您可以在同一个.cpp文件中进行此操作,将foo::freeStandingMethod()
放在foo::declaredMethod()
的另一个.cpp文件中也是合法的,此时这将变得不可能。< / p>
答案 7 :(得分:2)
这不是答案,但您可能会发现它内容丰富且有趣。 向您的类添加2个模板函数将有效地允许您调用任何将该类的对象作为第一个参数的自由函数:
#include <string>
#include <iostream>
struct puppy {
puppy(std::string name)
: _name(std::move(name))
{}
const std::string& name() const noexcept {
return _name;
}
void set_name(std::string name) {
_name = std::move(name);
}
template<class F, class ...Args>
auto perform(F&& f, Args&&...args) const
-> decltype(f(*this, std::forward<Args>(args)...))
{
return f(*this, std::forward<Args>(args)...);
}
template<class F, class ...Args>
auto perform(F&& f, Args&&...args)
-> decltype(f(*this, std::forward<Args>(args)...))
{
return f(*this, std::forward<Args>(args)...);
}
private:
std::string _name;
};
void woof(const puppy& p) {
std::cout << "puppy " << p.name() << " woofs!" << std::endl;
}
void indented_woof(const puppy&p, size_t indent) {
std::cout << std::string(indent, ' ');
woof(p);
}
void complex_woof(const puppy& p, int woofs)
{
std::cout << "attention!" << std::endl;
for (int i = 0 ; i < woofs ; ++i) {
p.perform(indented_woof, 4);
}
}
std::string name_change(puppy& p, std::string(new_name))
{
auto old_name = p.name();
p.set_name(std::move(new_name));
return old_name;
}
int main()
{
puppy fido { "fido" };
fido.perform(woof);
fido.perform(complex_woof, 10);
auto old_name = fido.perform(name_change, "bonzo");
fido.perform(woof);
std::cout << "changed name from " << old_name << std::endl;
return 0;
}
答案 8 :(得分:1)
why should declare these? I know for common c method, there is no need to declare, instead of it just define it:
C中没有方法,只是结构的属性,可以是函数Pointeur,然后关联到函数地址。
此外,您必须在类定义中声明它,原因与您在C中执行它的原因相同:
compilateur会将这个预先声明转换为函数pointeur,然后在你的对象的构造中与所述的方法相关联。
如果应该将C ++类的定义转换为C结构,则代码将如下所示:
struct Aclass {
void (*Amethode))(int);
}
void Amethode(int) { return (0); }
Aclass primaryObject = {&Amethode};
Aclass* AclassConstructor() {
Aclass* object;
object = malloc(sizeof(Aclass));
memcpy(object, primaryObject, sizeof(Aclass));
return (object);
}