A. c++问题。关于调用类的对象成员的成员函数
你的problem不是静态的不能通过类名调用,只能创建b类通过对象调用,而且a类的void
test()须是公有的.
#include
using
namespace
std;
class
A
{
public
:
void
test(){
cout<<"test
A";
}
static
void
stest(){
cout<<"static
test
A";
}
};
class
B
{
public:
void
test(){
a.test();
}
public
:
A
a;
static
A
sa;
};
int
main()
{
B
b;
b.test();
b.a.test();
B::sa.stest();
}
以上三种方法都正确,希望对你有用.
B. 关于一个java中成员函数的代码,无法编译,求解决答案,哪里出错。
你放置 p1.jisuan(); 的地方,是类初始化的区域,请把放到一个方法当中,或者把Person p1=new Person();
p1.jisuan();
放入static 代码化
C. 如果不将average函数定义为静态成员函数行不行程序能否编译需要做什么修改为什么要用静态成员函数
为什么要用静态成员函数?
从上述修改中可以看出,不使用静态成员函数显然也能实现相同的功能,那么,为什么要使用静态成员函数呢?
如果把average函数定义为非静态成员函数,那么主函数中将出现stud[1](当然,换成stud[0]或者stud[2]也可以),stud[1]的出现破坏了主函数中语句的逻辑性。他人在阅读主函数时看到stud[1]也许会有疑问:这里为什么要用stud[1]的成员函数,有什么特殊含义吗?是不是this指针必须在指向stud[1]的时候才能求得正确的平均值?降低了主函数的可读性。
静态成员函数主要是用来处理静态数据成员的,而静态数据成员不只属于某一个对象,它是为“全部同类对象”所共用的。因此,定义静态成员函数的目的在于处理“全部同类对象”的共同问题。
静态成员函数不属于某一个特定的对象,因为把一个处理“全部同类对象”共同问题的函数定义为某个对象所有是不合逻辑的。静态成员函数直接使用类名和域运算符调用,提高了语句的逻辑性和可读性。
楼上认为,使用静态成员函数的原因在于,不论有没有定义对象,静态成员函数都可以直接被调用。这的确是静态成员函数的一个特点,但是把它作为使用静态成员函数的原因未免有些牵强。试想,在没有定义对象的情况下,调用静态成员函数又有什么意义呢?
也许有人会说,在没有定义对象的情况下,静态成员函数还可以对静态数据成员进行操作啊。是的,的确可以,可是静态数据成员又是为谁而设的呢?没有定义对象,数据成员也变的没有意义了。
综上,静态成员函数的使用,提高了语句的逻辑性和可读性。
D. 类的有成员函数的声明但是没有实现为什么可以编译
可以编译,但链接会出错,因为这不是编译要检查的问题
E. 请问什么是成员函数的定义
成员函数相当于C或C++中的函数。你应该用如下的方式说明一个成员函数:
Type name (Parameter)
//function body
注意:每一个成员函数必须返回一个值或声明返回为空(void)。它返回类型的说明告诉编译器它将返回什么类型的值。在某些情况下,成员函数需要表示它是否成功的完成了它的工作,此时返回类型通常为布尔型的。参数表是用逗号分开的一组变量,它将为成员函数提供所需信息。
下面例子中定义了一个成员函数。通过它,你的矩形类可以计算自己的面积了:
int getArea(int w,int h)
{
int a;
a=w*h;
return a;
}
另外,矩形还需要对自己进行描绘,因此它需要成员函数drawRect(),此时,你的矩形类的定义将如下所示:
public class DrwRect
{
public static void main(String args[])
{
class Rectangle
{
int width,height,area;
public Rectangle(int w,int h)
{
width=w;
height=h;
area=getArea(w,h);
}
protected int getArea(int w,int h)
{
int a;
a=w*h;
return a;
}
public void drawRect()
{
int i,j;
for(i=width;i>0;i--)
System.out.print("#");
System.out.print("") ;
for(i=height-2;i>0;i--)
System.out.print("#");
for(j=width-2;i>0;j--)
System.out.print("");
System.out.print("#");
for(i=width;i>0;i--)
System.out.print("#");
System.out.print("");
}
} //Rectangle
int w=Integer.valueOf(args[0]).intValue();
int h=Integer.valueOf(args[1]).intValue();
Rectangle myrect=new Rectangle(w,h);
myrect.drawRect();
}
}
上例中最后一个“#”号后面还有一个System.out.print("")这是由于这个成员函数在上一行没有结束而且缓冲区没有溢出时将不把输出结果写屏。若你使用print成员函数,却没有得到输出,这时仔细确认一下你是否以""来结束你的输出流。
2:不同类型的成员函数
在上例的成员函数声明中你需要注意两点:getArea()定义为private型,drawRect()定义为public型。public型意味着任何类都可以调用它。private型,它只能被所声明的类内部调用。这些说明类型同样适用于数据变量。
若有人想改变一个私有变量,通常要引用下面的成员函数:
public void setWidth(int w)
{
width=w;
}
注意:在Java中,protected只是作为关键字出现,而没有相应的功能。
3:成员函数的重载
假如你必须在不同情况下发送不同的信息给同一个成员函数的话,该怎么办呢?你可以通过对此成员函数说明多个版本(version)的方法来实现重载。重载的本质是创建了一个新的成员函数:你只需给它一个不同的参数列表(parameterlist),如下例所示:
void get Area(int w,int h);
void get Area(float w,float h);
在第二种情况下,成员函数get Area()接受两个浮点变量作为它的参数,编译器根据调用时的不同参数来决定该调用哪一种成员函数,假如你把两个整数提供给成员函数,你就调用第一个成员函数;假如你把两个浮点数提供给成员函数,第二个成员函数就被调用。
4:静态成员
除了public、private和protected以外,你还可以把成员说明为static(静态)。static修饰符表明一个变量或成员函数对所有类的实例都是相同的,你也许想使用一个所有Rectangle类都可以使用的变量,来说明该类的版本(version),假如你把它说明成一个static,那么该变量将对该类的所有实例都是一样的,如:
static int version=1;
静态成员函数和静态变量的优点就在于他们能在没有创建类的任何一个实例的情况下被引用,引用时在“.”域前,可直接使用类名而无须使用对象名。例如,drawRect成员函数使用了System.out.println成员函数,但实际上你却未曾创建一个某个System类的对象,这正是因为out是System类的一个静态变量,所以你可以直接使用这个成员函数而无须定义一个System对象。
5:构造和析构成员函数
类有一个特殊的成员函数叫做构造成员函数,它通常用于初始化类的数据成员。在创建对象时,会自动调用类的构造成员函数。Java中的构造成员函数必须与该类具有相同的名字,另外,构造成员函数一般都应用public类型来说明,这样才能在程序任意的位置创建类的实例--对象。
下面是一个Rectangle类的构造成员函数,它带有两个参数,分别表示矩形的长和宽:
public Rectangle(int w,int h)
{
width=w;
height=h;
area=getArea(w,h);
}
除了构造成员函数以外,类还提供了析构成员函数,当对象被从内存中删除时,该成员函数将会被自动调用。通常,在析构成员函数内,你可以填写用来回收对象内部的动态空间的代码。
F. 关于c++中类成员函数问题
1. 在eat()函数中,使用了形如const void eat()的方式,这个在const的用法中叫做:用const 修饰函数的返回值。这种方法的好处,只有在返回值为指针时,才可以显现出来,就是说:函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。下面是我写的一段示例程序:
#include <iostream>
using namespace std;
int s=0;
const int *sum(int x,int y)
{
s=x+y;
return &s;
}
int main()
{
const int *p=NULL;//这里的指针p必须为const类型,否则编译错误
p=sum(1,2);
cout<<*p<<endl;
return 0;
}
2. 在sleep()函数中,使用了形如void sleep()const的方式,这个在const的用法中叫做:const 成员函数。这种方法要求:我们应该把不会修改数据成员(即函数中的变量)的函数声明为const 类型。好处是:如果在编写const 成员函数时,不慎修改了数据成员,或者调用了其它非const 成员函数,编译器将指出错误,这就会提高程序的健壮性。下面是示例程序:
class Stack
{
public:
void Push(int elem);
int Pop(void);
int GetCount(void) const; // const 成员函数
private:
int m_num;
int m_data[100];
};
int Stack::GetCount(void) const
{
++ m_num; // 编译错误,企图修改数据成员m_num
Pop(); // 编译错误,企图调用非const 函数
return m_num;
}
下面是关于Const函数的几点规则:
1. const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.
2. const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.
3. const成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.
4. 然而加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的const成员函数是可以修改它的.
G. C++中类成员函数未实现,是否能够编译链接通过
如果该成员函数没有被调用,那么就不会对编译连接产生影响,可以通过编译。
H. c++类成员函数在类外定义,编译错误!!!!!(3个文件)
你的分离编译错误,主要是因为你在main中include linkqueue.h,而link queue的实现放在了cpp中导致。这里你的main include的linkqueeu.cpp,所以不会导致问题。
模板的实现一般都需要放在头文件中,因为模板类似宏,编译器需要根据提供的模板参数生成代码,而如果编译器看到模板的实现,那么就生成不了代码,最后链接会出错。放在cpp里一般是你需要显式实例化模板,并且不想让用户随意对模板进行实例化,也就是用户只能使用你提供的特化。
//foo.h
template<typenameT>
structfoo{
voidf();
};
//foo.cpp
#include"foo.h"
template<typenameT>
voidfoo<T>::f(){...}
//
templateclassfoo<int>;//只允许用户使用int参数
一般不去includecpp文件,当然也不是完全不可以,因为只是一个文件而已。
你将linkqueue.cpp改成linkqueue.hpp或者linkqueue_impl.h等头文件命名,之后在linkqueue.h中include这个头文件,在main.cpp中只需要includelinkqueue.h即可。
头文件一般需要用#ifndef #endif包裹起来,否在可能会出现被多次include的问题,导致编译错误。
#ifndeffile_h
#definefile_h
//类定义,函数声明等
#endif
I. 什么叫成员函数有什么作用
什么是友元(friend)?
允许另一个类或函数访问你的类的东西。
友元可以是函数或者是其他的类。类授予它的友元特别的访问权。通常同一个开发者会出于技术和非技术的原因,控制类的友元和成员函数(否则当你想更新你的类时,还要征得其它部分的拥有者的同意)。
分清成员函数,非成员函数和友元函数
成员函数和非成员函数最大的区别在于成员函数可以是虚拟的而非成员函数不行。所以,如果有个函数必须进行动态绑定(见条款38),就要采用虚拟函数,而虚拟函数必定是某个类的成员函数。关于这一点就这么简单。如果函数不必是虚拟的,情况就稍微复杂一点。
看下面表示有理数的一个类:
class rational {
public:
rational(int numerator = 0, int denominator = 1);
int numerator() const;
int denominator() const;
private:
...
};
这是一个没有一点用处的类。(用条款18的术语来说,接口的确最小,但远不够完整。)所以,要对它增加加,减,乘等算术操作支持,但是,该用成员函数还是非成员函数,或者,非成员的友元函数来实现呢?
当拿不定主意的时候,用面向对象的方法来考虑!有理数的乘法是和rational类相联系的,所以,写一个成员函数把这个操作包到类中。
class rational {
public:
...
const rational operator*(const rational& rhs) const;
};
(如果你不明白为什么这个函数以这种方式声明——返回一个const值而取一个const的引用作为它的参数——参考条款21-23。)
现在可以很容易地对有理数进行乘法操作:
rational oneeighth(1, 8);
rational onehalf(1, 2);
rational result = onehalf * oneeighth; // 运行良好
result = result * oneeighth; // 运行良好
但不要满足,还要支持混合类型操作,比如,rational要能和int相乘。但当写下下面的代码时,只有一半工作:
result = onehalf * 2; // 运行良好
result = 2 * onehalf; // 出错!
这是一个不好的苗头。记得吗?乘法要满足交换律。
如果用下面的等价函数形式重写上面的两个例子,问题的原因就很明显了:
result = onehalf.operator*(2); // 运行良好
result = 2.operator*(onehalf); // 出错!
对象onehalf是一个包含operator*函数的类的实例,所以编译器调用了那个函数。而整数2没有相应的类,所以没有operator*成员函数。编译器还会去搜索一个可以象下面这样调用的非成员的operator*函数(即,在某个可见的名字空间里的operator*函数或全局的operator*函数):
result = operator*(2, onehalf); // 错误!
但没有这样一个参数为int和rational的非成员operator*函数,所以搜索失败。
再看看那个成功的调用。它的第二参数是整数2,然而rational::operator*期望的参数却是rational对象。怎么回事?为什么2在一个地方可以工作而另一个地方不行?
秘密在于隐式类型转换。编译器知道传的值是int而函数需要的是rational,但它也同时知道调用rational的构造函数将int转换成一个合适的rational,所以才有上面成功的调用(见条款m19)。换句话说,编译器处理这个调用时的情形类似下面这样:
const rational temp(2); // 从2产生一个临时
// rational对象
result = onehalf * temp; // 同onehalf.operator*(temp);
当然,只有所涉及的构造函数没有声明为explicit的情况下才会这样,因为explicit构造函数不能用于隐式转换,这正是explicit的含义。如果rational象下面这样定义:
class rational {
public:
explicit rational(int numerator = 0, // 此构造函数为
int denominator = 1); // explicit
...
const rational operator*(const rational& rhs) const;
...
};
那么,下面的语句都不能通过编译:
result = onehalf * 2; // 错误!
result = 2 * onehalf; // 错误!
这不会为混合运算提供支持,但至少两条语句的行为一致了。
然而,我们刚才研究的这个类是要设计成可以允许固定类型到rational的隐式转换的——这就是为什么rational的构造函数没有声明为explicit的原因。这样,编译器将执行必要的隐式转换使上面result的第一个赋值语句通过编译。实际上,如果需要的话,编译器会对每个函数的每个参数执行这种隐式类型转换。但它只对函数参数表中列出的参数进行转换,决不会对成员函数所在的对象(即,成员函数中的*this指针所对应的对象)进行转换。这就是为什么这个语句可以工作:
result = onehalf.operator*(2); // converts int -> rational
而这个语句不行:
result = 2.operator*(onehalf); // 不会转换
// int -> rational
第一种情形操作的是列在函数声明中的一个参数,而第二种情形不是。
尽管如此,你可能还是想支持混合型的算术操作,而实现的方法现在应该清楚了:使operator*成为一个非成员函数,从而允许编译器对所有的参数执行隐式类型转换:
class rational {
... // contains no operator*
};
// 在全局或某一名字空间声明,
// 参见条款m20了解为什么要这么做
const rational operator*(const rational& lhs,
const rational& rhs)
{
return rational(lhs.numerator() * rhs.numerator(),
lhs.denominator() * rhs.denominator());
}
rational onefourth(1, 4);
rational result;
result = onefourth * 2; // 工作良好
result = 2 * onefourth; // 万岁, 它也工作了!
这当然是一个完美的结局,但还有一个担心:operator*应该成为rational类的友元吗?
这种情况下,答案是不必要。因为operator*可以完全通过类的公有(public)接口来实现。上面的代码就是这么做的。只要能避免使用友元函数就要避免,因为,和现实生活中差不多,友元(朋友)带来的麻烦往往比它(他/她)对你的帮助多。
然而,很多情况下,不是成员的函数从概念上说也可能是类接口的一部分,它们需要访问类的非公有成员的情况也不少。
让我们回头再来看看本书那个主要的例子,string类。如果想重载operator>>和operator<<来读写string对象,你会很快发现它们不能是成员函数。如果是成员函数的话,调用它们时就必须把string对象放在它们的左边:
// 一个不正确地将operator>>和
// operator<<作为成员函数的类
class string {
public:
string(const char *value);
...
istream& operator>>(istream& input);
ostream& operator<<(ostream& output);
private:
char *data;
};
string s;
s >> cin; // 合法, 但
// 有违常规
s << cout; // 同上
这会把别人弄糊涂。所以这些函数不能是成员函数。注意这种情况和前面的不同。这里的目标是自然的调用语法,前面关心的是隐式类型转换。
所以,如果来设计这些函数,就象这样:
istream& operator>>(istream& input, string& string)
{
delete [] string.data;
read from input into some memory, and make string.data
point to it
return input;
}
ostream& operator<<(ostream& output,
const string& string)
{
return output << string.data;
}
注意上面两个函数都要访问string类的data成员,而这个成员是私有(private)的。但我们已经知道,这个函数一定要是非成员函数。这样,就别无选择了:需要访问非公有成员的非成员函数只能是类的友元函数。
本条款得出的结论如下。假设f是想正确声明的函数,c是和它相关的类:
·虚函数必须是成员函数。如果f必须是虚函数,就让它成为c的成员函数。
·operator>>和operator<<决不能是成员函数。如果f是operator>>或operator<<,让f成为非成员函数。如果f还需要访问c的非公有成员,让f成为c的友元函数。
·只有非成员函数对最左边的参数进行类型转换。如果f需要对最左边的参数进行类型转换,让f成为非成员函数。如果f还需要访问c的非公有成员,让f成为c的友元函数。
·其它情况下都声明为成员函数。如果以上情况都不是,让f成为c的成员函数。
回答者:Dyemn - 高级经理 六级 12-27 08:29
友元函数要在一个类体内说明,形式为:
friend 类型名 友元函数名(形参表);
然后在类体外对友元函数进行定义,定义的格式和普通函数相同,但可以通过对象作为参数直接访问对象的私有成员
友元函数说明如下:
1)必须在类的说明中说明友元函数,说明时以关键字friend开头,后跟友元函数的函数原型,友元函数的说明可以出现在类的任何地方,包括在private和public部分;
2)注意友元函数不是类的成员函数,所以友元函数的实现和普通函数一样,在实现时不用"::"指示属于哪个类,只有成员函数才使用"::"作用域符号;
3)友元函数不能直接访问类的成员,只能访问对象成员,
4)友元函数可以访问对象的私有成员,但普通函数不行;
5)调用友元函数时,在实际参数中需要指出要访问的对象,
J. 一个C++头文件与成员函数编译为目标文件封装的问题
除了头文件以外的文件只要文件里面声明定义都能找的到就可以编译成单独的目标文件(事实上很多编译器也正是这样做的),编译之后确实可以这样子使用,但是经过编译之后很多函数的代码都会出席那改变,那时候就不知道你打算怎么用了