如果只定义这个方法,它将会有一个编译器错误。为什么必须在C++类定义中声明一个方法?
void classA::testMethod() {
}
所以它必须首先声明:
class classA {
void testMethod();
};
为什么这些声明?
我知道它是不是需要申报常见的C方法的方法,但是他们可以定义为:
void test() {
}
如果只定义这个方法,它将会有一个编译器错误。为什么必须在C++类定义中声明一个方法?
void classA::testMethod() {
}
所以它必须首先声明:
class classA {
void testMethod();
};
为什么这些声明?
我知道它是不是需要申报常见的C方法的方法,但是他们可以定义为:
void test() {
}
有几个次要的原因客观和主观(即允许指定可见性,作为类的接口,可能还有其他几个与编译和链接阶段和TU符号有关的其他原因的可见性,更不用提一类是基本封装单元,与所有的暗示),但不容置疑之一是的标准规定它:
N3797 - class.mfct/P2
甲成员函数可以在i中定义(8.4) ts类的定义,在 这种情况下它是内联成员函数(7.1.2),或者它可能是在其类定义之外定义的 ,如果它已经声明了但未在其类定义中定义的 。在类定义之外出现的成员函数 定义应在包含类定义的名称空间范围中出现 。除类别定义以外的成员 功能定义和 类别 类别的成员函数的显式特殊化和成员函数模板(14.7)出现在类别定义之外的 以外,不应重新声明成员函数。
强调我的。
不用担心,谢谢你解决这个问题! – 2014-09-26 12:15:00
它有助于封装。如果你有一个A级
class A {
public:
foo();
bar();
}
你可以肯定,只有方法foo
和bar
惹类的私有数据成员。 (或指针魔术或当然未定义的行为)
我不明白这是如何相关的。 – user2864740 2014-09-26 09:01:14
@ user2864740可以定义独立的'void classA :: testMethod(){...}'表示您想要扩展该类。但在C++中情况并非如此。 – Csq 2014-09-26 09:03:33
封装与这些有什么关系? C++ *可能被定义为执行一些愚蠢的魔术,例如将这些找到的定义提升为类定义(这没什么意义,特别是鉴于定义通常与实现分离)。但这些都与封装无关。 – user2864740 2014-09-26 09:06:22
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同样的原因:
的compilateur将改变这种预申报成一个函数pointeur再联想到上述梅索德INT的建设你的对象。
如果一个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);
}
你是否声称在C++中的成员函数是通过函数指针属性来实现的?事实并非如此。成员函数是由编译器静态定义和静态解析的。函数指针在使用虚拟函数时进入它,但采用与我认为你描述的方式不同的方式。 – 2014-09-26 09:07:23
@Magnus Hoff事实上,你是对的,事实并非如此,但对于一个首次亮相的程序员来说,它更容易理解,或者我认为是这样...... – CollioTV 2014-09-26 09:11:00
虽然你所描述的方案可行,但它并不代表实际发生的事情因此令人困惑。我认为以下几点更容易理解,除了更接近地表示实际发生的情况外:http://ideone.com/4xhr8T – 2014-09-26 09:15:14
你并不需要你定义它之前声明的方法,但是你需要在类中声明类方法。否则它不会是一个类方法。
这似乎是一个矛盾,但定义也是一个声明。所以,这是什么意思是,这一定义可能出现在类本身:
class A {
void testMethod() { /*...*/ }
};
[编辑] 此外,实际而言,类声明中有private
,protected
和public
部分。这是封装所必需的。如果你可以在类之外声明方法,你将失去封装。任何人都可以通过定义额外的获取者和设置者来访问私有成员,即使这些成员没有意义。类不变量将变得毫无意义。
@TonyD你不会降低其他问题以获得另一个答案,这是你的个人意见,而其他人可能会不同意。现在我明白谁也低估了我的回答。如果答案是错误/无用的,那么你的意图就是失望,如果你觉得有一个更好的或者你最喜欢的答案,那么你的意图就会降低。 – 2014-09-26 10:02:22
“如果你能在课堂外声明方法,你将失去封装。”当然,你可以通过在Java的每个方法定义上允许访问修饰符来解决这个问题。 – 2014-09-27 08:21:26
“方法”或“成员函数”(正如C++中更常见的术语)是类声明的一部分。既然你必须在一个地方声明一个C++类,你必须确保所有的“成员函数”(或“方法”)已经存在于该声明中。
我知道它是不是需要申报常见的C方法的方法,但是当你是指C++中的“常见的C法”,他们 正好可以定义
,实际上指的是“共同功能”。请注意,您可以在任何声明此类函数的地方声明类。
此外,请注意,您可以声明一个正文的成员函数。您不必单独声明和定义。即这是完全有效的:
class A{
void privateMethod() {
// do something here...
}
public:
void publicMethod() {
// do something here...
}
};
请注意使用限定符::
。这意味着
所以写void A::testMethod()
假设有一个类或名称空间A
定义 - 这是如何定义C++。这适用于
void A::testMethod();
以及为
void A::testMethod()
{
}
另外请注意,你必须确实没有在::
左侧为
void ::testMethod()
{
}
根据定义的全局命名空间全局名称空间总是被定义的,所以上面的代码定义了一个类似于没有限定符的C风格的函数。
即使它没有被标准强制规定,为什么需要在类定义中声明所有的类方法还有以下两个原因。
您只能在类声明中声明为public,private或protected,但不能在.cpp文件的方法定义中这样做。那么你的独立式课堂方法有什么可见性?
如果标准决定选择其中一个作为默认值(C++默认为私有),并将该可见性放在您的方法上,则您现在有一个范围问题。即使是最严格的可见性(私有),也意味着您可以在任何其他成员方法中使用该方法,包括在源文件之前定义的那些成员方法。如果没有类定义中的声明,那些早期的函数将不会意识到您的自由站立方法,因此您违反了范围规则。
在你的了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;
}
回答(现在删除)的评论: 执行的一个版本必须是const以支持采用非常量小狗&的函数。 – 2014-09-26 11:15:30
以前所有的答案是正确的,只要他们去,但他们没有指出规则背后的原因。在C++中, 类定义已关闭;你以后不能添加它。这个 对于非静态数据成员是必需的,因为它们决定了大小(以及隐式生成的特殊函数) ,但它是C++中所有类成员的基本原则:不仅仅是 数据,而是函数,类型,对于 好封装被认为是必不可少的。
对于支持类概念的大多数(但不是全部)语言都是如此。
这也解释了为什么它的情况不同于 名称空间(它们没有关闭)。
+1(早期),但公平性“以前的所有答案”,除Csq's外。 – 2014-09-26 11:16:27
你可以在c中声明类之外的函数 – jonynz 2014-09-26 09:01:09
@jonynz:这没有意义,C没有类或方法。 – MSalters 2014-09-26 09:06:04
采取了一点,谢谢 – jonynz 2014-09-26 09:07:34