为什么必须在C++类定义中声明一个方法

Why must a method be declared in a C++ class definition?

本文关键字:方法 一个 声明 C++ 定义 为什么      更新时间:2023-10-16

如果只定义此方法,则会出现编译器错误。

void classA::testMethod() {    
}

因此必须首先声明:

class classA {    
   void testMethod();
};

为什么要宣布这些?

我知道对于常见的C方法,它不需要声明,但它们可以定义:

void test() {
}

有几个次要的客观和主观原因(即允许指定可见性,充当类的接口,可能还有其他几个与编译和链接阶段和TU符号可见性有关的原因,更不用说类是基本的封装单元,这一切都意味着),但一个毋庸置疑的原因是标准规定

N3797-等级.mfct/p2

成员函数可以在其类定义中定义(8.4),在在这种情况下,它是一个内联成员函数(7.1.2),或者它可能是在其类定义之外定义,如果它已经已声明但未在其类定义中定义成员函数出现在类定义之外的定义应出现在包含类定义的命名空间范围中。成员除外出现在类定义之外的函数定义,以及除了类的成员函数的显式专门化模板和成员函数模板(14.7)出现在类定义,成员函数不应重新声明。

重点是我的。

在定义方法之前不需要声明该方法,但需要在类中声明类方法。否则它就不是一个类方法。

这看起来可能有点矛盾,但定义也是一种宣言。因此,这意味着定义可能出现在类本身中:

class A {
  void testMethod() { /*...*/ } 
};

[编辑]此外,实际上,在类声明中有privateprotectedpublic部分。这是封装所必需的。如果可以在类之外声明方法,则会丢失封装。任何人都可以通过定义额外的getter和setter来访问私人成员,即使这些都没有意义。类不变量将变得毫无意义。

它有助于封装。如果你有a级

class A {
public:
  foo();
  bar();
}

可以肯定的是,只有方法foobar会干扰类的私有数据成员。(当然是指针魔术或未定义的行为)

之前的所有答案都是正确的,但是他们没有指出这条规则背后的原因。在C++中,类定义是封闭的;以后不能添加到其中。这对于非静态数据成员是必需的,因为它们确定大小(以及隐式生成的特殊函数),但是这是C++中所有类成员的基本原则:数据,但函数、类型等良好的封装。

对于大多数(但不是所有)支持阶级的概念。

这也解释了为什么情况不同命名空间(未关闭)。

注意限定符::的使用。意思是

  • 在左边有一个名称空间或类标识符
  • 右边有一个名称空间、类或方法/函数标识符

因此,编写void A::testMethod()假设定义了一个类或名称空间A——C++就是这样定义的。这适用于

void A::testMethod();

以及

void A::testMethod()
{
}

还要注意全局名称空间,在这里::的左侧实际上没有任何内容,就像中一样

void ::testMethod()
{
}

根据定义,全局名称空间总是被定义的,所以上面的代码定义了一个类似于C风格的函数,没有限定符。

即使标准没有强制要求,也有以下两个原因需要在类定义中声明所有类方法。

  1. 您只能在类声明中将某些东西声明为public、private或protected,而不能在.cpp文件中的方法定义中这样做。那么,你的独立类方法会有什么可见性呢?

  2. 如果标准决定选择三者中的一个作为默认值(C++默认为private),并将该可见性放在方法上,那么现在就存在范围界定问题。即使是最严格的可见性(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文件,这样就不可能了。

这不是一个答案,但你可能会发现它信息丰富且有趣。在类中添加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;
}

"方法"或"成员函数"(C++中更常见的术语)是类声明的一部分。由于必须在一个地方声明C++类,因此必须确保该声明中已经存在所有"成员函数"(或"方法")。

我知道对于常见的C方法,它不需要声明,但它们可以定义为

当你在C++中提到"公共C方法"时,你实际上指的是"公共函数"。请注意,您可以在任何可以声明此类函数的地方声明类。

另外,请注意,您可以使用主体声明成员函数。您不必将声明和定义分开。也就是说,这是完全有效的:

class A{
   void privateMethod() {
       // do something here...
   }
public:
   void publicMethod() {
       // do something here...
   }
};

why should declare these? I know for common c method, there is no need to declare, instead of it just define it:

C中没有方法,只有结构的属性,它可以是函数Pointeur,然后关联到函数addresse。

此外,您必须在类定义中声明它,原因与您在C:中声明的原因相同

编译程序将把这个预声明转换成一个函数指针,然后在对象的构造中与所述方法相关联。

如果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);
}