no_rain

C++的一个语法问题

今天看到《C++ primer》上说:可以用派生类对象初始化基类对象,根据是派生类对象可以赋值给基类的对象的引用。这里我觉得有个语义上的问题:派生类在继承基类的时候,基类的private成员是不可见的,那么基类初始化private对象的时候,就用了派生类的不可见成员去初始化它了。
先贴段测试代码:
 1 #include<iostream>
 2 using namespace std;
 3 class A
 4 {
 5       int mem1,mem2;
 6 public:
 7        A(const A& a);
 8        A(int a, int b):mem1(a),mem2(b){}
 9        int fun1(){return mem1;}
10        int fun2(){return mem2;}
11 };
12 A::A(const A& a)
13 {
14            mem1 = a.mem1;
15            mem2 = a.mem2;
16            cout << "A's copy constructor called"<<endl;
17 }
18 class B : public A
19 {
20       int mem3;
21 public:
22   B(int a, int b, int c): A(a,b),mem3(c){}
23     int fun3(){return fun1()};
24 };
25 int main()
26 {
27     B b(1,2,3);
28     A aob(b);
29 }
30 
这段代码输出:A's copy constructor called(这是用G++编译器的,DEV C++ 编译通过,可是运行没有输出)
确实如书上说的派生类对象可以赋值给基类的对象的引用,所以调用了拷贝构造函数。其实根据《inside the C++ object model》的说法,派生类的对象中将会保存基类的non-static数据成员的,那么即使不可见,可以用来初始化也在情理之中。
可是再看被初始化对象调用其成员函数的代码:
 1 #include<iostream>
 2 using namespace std;
 3 class A
 4 {
 5       int mem1,mem2;
 6 public:
 7        A(const A& a);
 8        A(int a, int b):mem1(a),mem2(b){}
 9        int fun1(){return mem1;}
10        int fun2(){return mem2;}
11 };
12 A::A(const A& a)
13 {
14            mem1 = a.mem1;
15            mem2 = a.mem2;
16            cout << "A's copy constructor called"<<endl;
17 }
18 class B : public A
19 {
20       int mem3;
21 public:
22   B(int a, int b, int c): A(a,b),mem3(c){}
23     int fun3(){return fun1()};
24 };
25 int main()
26 {
27     B b(1,2,3);
28     A aob(b);
29     cout <<aob.fun1() << aob.fun2();//the //difference
30 }
31 
这就编译错误了:tess.cpp:28:36: error: request for member ‘fun2’ in ‘aob’, which is of non-class type ‘A(B)’这在两个上述编译器都是这样的结果。那么这个对象就无法调用基类的函数了。
我个人肤浅的推断:A(B)将被编译器认为是一种新的类型对待,那么怎么确定这种类型的接口函数呢?这不就有问题了吗?
我再多此一举的实验下如下代码:
 1 #include<iostream>
 2 using namespace std;
 3 class A
 4 {
 5       int mem1,mem2;
 6 public:
 7        A(const A& a);
 8        A(int a, int b):mem1(a),mem2(b){}
 9        int fun1(){return mem1;}
10        int fun2(){return mem2;}
11 };
12 A::A(const A& a)
13 {
14            mem1 = a.mem1;
15            mem2 = a.mem2;
16            cout << "A's copy constructor called"<<endl;
17 }
18 class B : public A
19 {
20       int mem3;
21 public:
22   B(int a, int b, int c): A(a,b),mem3(c){}
23     int fun3(){return fun1();}
24 };
25 int main()
26 {
27     B b(1,2,3);
28     A aob(b);
29     cout <<aob.fun3();// the difference
30 }
31 
结果是编译错误:‘class A’ has no member named ‘fun3’这一点也不意外,那么这样的对象不就真的没有了接口了?小弟我虚心等待大牛们的解答,希望能在原理上给俺个解释,不胜感激!

posted on 2012-03-16 21:13 is-programmer 阅读(1524) 评论(11)  编辑 收藏 引用

评论

# re: C++的一个语法问题 2012-03-16 22:15 远行

大哥,你第二个和第三个例子好像有错误,class B 里面的fun3,那个;打错地方了,我试了下都编译不过了,我改了就可以调用了。。。

第三个例子的话,这个接口跟对象关系不大吧,接口还是个函数地址,只是用该类对象调用的时候,附带多传了个该对象的地址过去,class A的对象是绝对不能在编译层次上调用class B中的函数的  回复  更多评论   

# re: C++的一个语法问题 2012-03-16 23:29 is-programmer

@远行
谢谢你的回复!
我第三个例子的fun3()的分号应该是放在括号内的~这个我改过来了。可是还是
tess.cpp:29:16: error: ‘class A’ has no member named ‘fun3’(g++ (GCC) 4.6.2);
我想说的是A(B)即由派生类对象初始化的基类对象为什么就这么不伦不类,A的函数不能调用,B的函数不能调用?  回复  更多评论   

# re: C++的一个语法问题 2012-03-16 23:46 远行

怎么说了,子类可以初始化基类,但是无论怎么样基类对象不可以调用子类的方法,至于为什么,inside c++ model中说的很清楚,
从设计意义上讲子类对象一定是一个基类对象,所以c++设计成子类默认可以初始化基类,但是方法和数据很不相同吧,函数毕竟只是个代码的地址,类的成员函数也只是多了个this指针参数,基类对象调用子类中的方法一点意义都没有,
如果真想这样,多态就是这样做的,只是方法必须是虚函数,而且要用引用或者指针去调用@is-programmer
  回复  更多评论   

# re: C++的一个语法问题 2012-03-17 09:27 tb

调试不过啊   回复  更多评论   

# re: C++的一个语法问题 2012-03-17 12:09 izualzhy

第二个为什么我的可以通过?结果跟你不一样?
zhaoyu@ubuntu:~$ ./test
A's copy constructor called
12zhaoyu@ubuntu:~$ g++ -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.4.3-4ubuntu5.1' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --program-suffix=-4.4 --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i486 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix
gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1)   回复  更多评论   

# re: C++的一个语法问题 2012-03-17 13:30 路过

@is-programmer

编译器不对吧,eclipse + mingw gcc4.6.1,aob.func1() 和 aob.func2() 都能正确编译、执行;aob.func3() 显然不能决议,没有这个成员函数。  回复  更多评论   

# re: C++的一个语法问题 2012-03-17 13:30 is-programmer

@远行
谢谢!你说的这个我明白,但是问题是用子类对象初始化的基类对象,它连自己(基类自己的函数)调用都会编译错误呢?  回复  更多评论   

# re: C++的一个语法问题 2012-03-17 13:42 is-programmer

@izualzhy
谢谢!
确实是编译器的问题~这个是在DEV C++的编译器下才会出现的问题。。。唉DEV C++ 是很久以前开发的,都很久没有跟新了,所以~~~
对不起各位,在G++下是可以正常编译,运行也是正常的,(除了测试代码3,本身就是错的)。  回复  更多评论   

# re: C++的一个语法问题 2012-03-17 13:48 is-programmer

@izualzhy
g++ (GCC) 4.6.2 20111027 (Red Hat 4.6.2-1)
Copyright (C) 2011 Free Software Foundation, Inc.
你的编译器可以去跟新了,呵呵。我也编译过了,昨天忘记是什么情况了。DEV——C++编译不过  回复  更多评论   

# re: C++的一个语法问题 2012-03-17 14:16 远行

自己的函数调用不可能出错吧,你去试一下,你这里是调用子类的函数才编译不过,而且是在静态调用@is-programmer
  回复  更多评论   

# re: C++的一个语法问题 2012-03-19 09:57 mendynew

所谓的”不可见“特性是指在B以及其对象中无法直接操作A中的私有成员,但是通过拷贝构造函数B的对象向上转型成A,A的拷贝构造函数里自然能操作了。
有一点一定要记住,你的这几个例子都是在编译器决定的,C++的编译器实现了该语法特性。  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

<2012年3月>
26272829123
45678910
11121314151617
18192021222324
25262728293031
1234567

统计

常用链接

留言簿

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜