为什么会有“error: declaration of ‘A ca’ shadows a parameter”的错误?

luosimuer 2013-11-19 01:48:32
我看书上写派生类构造函数只能合法调用其直接基类的构造函数,如果调用其非直接基类的构造函数是错误的。我自己试着写了这样的一个多继承函数,具体见下面代码,但是编译之后报如下错误:
4_4_4.cpp: In constructor ‘C::C(int, int, int)’:
4_4_4.cpp:37: error: declaration of ‘A ca’ shadows a parameter
不知道为什么,请大家帮我解释一下!


#include <iostream>

using namespace std;

class A
{
public:
A (int aa = 0) : a(aa)
{
cout << "call A ()" << endl;
}

private:
int a;
};


class B : public A
{
public:
B (int ba = 0, int bb = 0) : A(ba), b(bb)
{
cout << "call B ()" << endl;
}

private:
int b;
};


class C : public B
{
public:
C (int ca = 0, int cb = 0, int cc = 0)
: B(ca, cb), c(cc)
{
A (ca);

cout << "call C ()" << endl;
}

private:
int c;
};


int main ()
{
C tmp (1, 2, 3);

return 0;
}



如果我把代码写为下面这样,就会报如下错误:
4_4_5.cpp: In constructor ‘C::C(int, int, int)’:
4_4_5.cpp:35: error: type ‘A’ is not a direct base of ‘C’
这个错误才是书上写的真正意思吧?那么为什么上面的代码会报不同的错误呢?


#include <iostream>

using namespace std;

class A
{
public:
A (int aa = 0) : a(aa)
{
cout << "call A ()" << endl;
}

private:
int a;
};


class B : public A
{
public:
B (int ba = 0, int bb = 0) : A(ba), b(bb)
{
cout << "call B ()" << endl;
}

private:
int b;
};


class C : public B
{
public:
C (int ca = 0, int cb = 0, int cc = 0)
: A(ca), B(ca, cb), c(cc)
{
cout << "call C ()" << endl;
}

private:
int c;
};


int main ()
{
C tmp (1, 2, 3);

return 0;
}


...全文
2170 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
luosimuer 2013-11-19
  • 打赏
  • 举报
回复
引用 2 楼 lm_whales 的回复:
[quote=引用 1 楼 go_and_see 的回复:]

class C : public B 
{
public:
	C (int ca = 0, int cb = 0, int cc = 0)
		: B(ca, cb), c(cc)
	{
		//A (ca);	// 需要注释掉
		cout << "call C ()" << endl;
	}
private:
	int c;
};
//A (ca); // 需要注释掉, 因为不注释,没有这样的语法!! 这个 1)不是定义变量,函数。 2)也不是初始化表。 3)也不是其他合法语句。 这个是理所当然的错误。 [/quote]我的这句A (ca);的本意是想显示调用从类A继承下来的类A的构造函数的,不知道为什么会有错呢?是不是不能在派生类中显示调用基类的构造函数呢?
luosimuer 2013-11-19
  • 打赏
  • 举报
回复
引用 11 楼 zsq765561964 的回复:
[quote=引用 5 楼 jievisionvanish 的回复:] [quote=引用 4 楼 go_and_see 的回复:] [quote=引用 3 楼 jievisionvanish 的回复:] 我的这句A (ca);的本意是想显示调用从类A继承下来的类A的构造函数的,不知道为什么会有错呢?是不是不能在派生类中显示调用基类的构造函数呢?
因为你在B的出始化列表里已经写过A的构造,B会构造A,所以这个出错的语句没必要存在。[/quote] 现在很不解的问题是:我有2个代码,都是在派生类中显示调用基类的构造函数,其中1.cpp有错误,2.cpp却可以正常编译,不知道为什么?在派生类里面显示调用构造函数确实是很怪而且基本不会这么用(因为调用之后也并不会改变之前隐式调用或者用初始化成员列表去初始化的基类的对象的值---这点我用程序测试过)。不过我确实想知道这样写为什么会导致编译错误的原因,还请大家帮帮忙! 代码1.cpp 编译会报错

#include <iostream>

using namespace std;

class A
{
public:
	A (int aa = 0) : a(aa)
	{
		cout << "call A ()" << endl;
	}

private:
	int a;
};


class B : public A
{
public:
	B (int ba = 0, int bb = 0) : b(bb)
	{
		A (ba);//这里显示调用基类的构造函数 会报错 程序2.cpp中却不会 不知为何?
		cout << "call B ()" << endl;
	}

private:
	int b;
};


int main ()
{
	B tmp (1, 2);

	return 0;
}
编译之后报错: g++ 1.cpp 1.cpp: In constructor `B::B(int, int)': 1.cpp:24: error: declaration of 'A ba' shadows a parameter 代码2.cpp,可以正常编译和执行

#include <iostream>

using namespace std;

class A
{
public:
	A (int aa = 0) : a(aa)
	{
		cout << "call A ()" << endl;
	}

private:
	int a;
};


class B : public A
{
public:
	B (int ba = 0, int bb = 0) : A(ba), b(bb)
	{
		cout << "call B ()" << endl;
	}

private:
	int b;
};


class C : public B 
{
public:
	C (int ca = 0, int cb = 0, int cc = 0)
	  : c(cc)
	{
		B (ca, cb);//这里也是显示调用基类的构造函数,为什么不会报错呢?
		
		cout << "call C ()" << endl;
	}

private:
	int c;
};


int main ()
{
	C tmp (1, 2, 3);

	return 0;
}

运行结果如下: g++ 2.cpp ./a.out call A () call B () call A () call B () call C ()[/quote] 确实出现此问题,同时,我发现当类B在类C的初始化列表中初始化时,结果为

call A()
call B()
call C()
希望得到解释[/quote] 如果将类C的初始化列表写为

C (int ca = 0, int cb = 0, int cc = 0)
	  : B(ca, cb), c(cc)
{
   ……
}
这时候相当于给基类B的构造函数传递了值,出现 call A() call B() call C() 结果的原因是由于类C是从类B继承下来的,所以构造类C会先构造类B,即调用类B的构造函数。而类B又是从类A继承下来的,所以构造类B会先构造类A。所以是这个结果。
luosimuer 2013-11-19
  • 打赏
  • 举报
回复
引用 13 楼 todd_leftcode 的回复:
B(ca, cb) 不是“调用B类的构造函数”(这是一个典型的坑) B(ca, cb)是声明一个匿名的B类型的变量(anonymous variable 或者 temporary variable,我也搞不清哪个是官方叫法),该变量的作用域为当前表示式。 比如
function foo(const string& str) { /*..do something with str..*/ }
foo(string("wtf")); // 这里的 string("wtf") 与 B(ca, cb) 异曲同工
嗯 我明白了 非常感谢!
todd_leftcode 2013-11-19
  • 打赏
  • 举报
回复
B(ca, cb) 不是“调用B类的构造函数”(这是一个典型的坑) B(ca, cb)是声明一个匿名的B类型的变量(anonymous variable 或者 temporary variable,我也搞不清哪个是官方叫法),该变量的作用域为当前表示式。 比如
function foo(const string& str) { /*..do something with str..*/ }
foo(string("wtf")); // 这里的 string("wtf") 与 B(ca, cb) 异曲同工
luosimuer 2013-11-19
  • 打赏
  • 举报
回复
引用 10 楼 todd_leftcode 的回复:
g++的错误信息还是比较明了的。 你声明了一个变量ca,这个变量遮住了参数里的ca变量,但这是不允许的,因为这两个ca在同一个作用域中。
A (ca);
表示声明一个A类型的变量 ca, 等价于
A ca;
A (ca + 0);
则表示用参数(ca+0)构造一个A类型的匿名对象。同理
B (ca, cb);
表示使用参数 ca, cb 构造一个匿名的B类对象。 这是由于编译器解析时语法优先级(我造的词)的原因造成的吧,看上去像是变更声明的换变量声明算,否则才考虑是不是是匿名变量构造(匿名变量用得少,所以优先级低吧) 无论如何,以上写法都不是调用基类或祖先类的构造函数的合法途径。首先要说,无论你写不写,基类的构造函数都会在任何一个本类声明的变量构造之前被调用,所以: 1. 基类的构造函数只能在初始化列表中调用 2. 无法隔代调用祖先类构造函数,因为这些函数已经被基类构造函数隐式调用过了,显示调用会引起重复构造,这是不允许的。
嗯 关于编译报错的问题我明白了,解释的很清楚 另外一个问题就是关于“无法隔代调用祖先类构造函数,因为这些函数已经被基类构造函数隐式调用过了,显示调用会引起重复构造,这是不允许的。”这句话,我的2.cpp中:
C (int ca = 0, int cb = 0, int cc = 0)
      : c(cc)
    {
        B (ca, cb);
         
        cout << "call C ()" << endl;
    }
类C是类B派生出来的,在构造类C之前已经隐式调用了类B的构造函数了,我在类C的构造函数中又显示调用了类B的构造函数,这时为什么不算是重复构造呢?是不是只有隔代继承才有这种重复构造的说法呢?不知道我的理解对不对呢?
zsq765561964 2013-11-19
  • 打赏
  • 举报
回复
引用 5 楼 jievisionvanish 的回复:
[quote=引用 4 楼 go_and_see 的回复:] [quote=引用 3 楼 jievisionvanish 的回复:] 我的这句A (ca);的本意是想显示调用从类A继承下来的类A的构造函数的,不知道为什么会有错呢?是不是不能在派生类中显示调用基类的构造函数呢?
因为你在B的出始化列表里已经写过A的构造,B会构造A,所以这个出错的语句没必要存在。[/quote] 现在很不解的问题是:我有2个代码,都是在派生类中显示调用基类的构造函数,其中1.cpp有错误,2.cpp却可以正常编译,不知道为什么?在派生类里面显示调用构造函数确实是很怪而且基本不会这么用(因为调用之后也并不会改变之前隐式调用或者用初始化成员列表去初始化的基类的对象的值---这点我用程序测试过)。不过我确实想知道这样写为什么会导致编译错误的原因,还请大家帮帮忙! 代码1.cpp 编译会报错

#include <iostream>

using namespace std;

class A
{
public:
	A (int aa = 0) : a(aa)
	{
		cout << "call A ()" << endl;
	}

private:
	int a;
};


class B : public A
{
public:
	B (int ba = 0, int bb = 0) : b(bb)
	{
		A (ba);//这里显示调用基类的构造函数 会报错 程序2.cpp中却不会 不知为何?
		cout << "call B ()" << endl;
	}

private:
	int b;
};


int main ()
{
	B tmp (1, 2);

	return 0;
}
编译之后报错: g++ 1.cpp 1.cpp: In constructor `B::B(int, int)': 1.cpp:24: error: declaration of 'A ba' shadows a parameter 代码2.cpp,可以正常编译和执行

#include <iostream>

using namespace std;

class A
{
public:
	A (int aa = 0) : a(aa)
	{
		cout << "call A ()" << endl;
	}

private:
	int a;
};


class B : public A
{
public:
	B (int ba = 0, int bb = 0) : A(ba), b(bb)
	{
		cout << "call B ()" << endl;
	}

private:
	int b;
};


class C : public B 
{
public:
	C (int ca = 0, int cb = 0, int cc = 0)
	  : c(cc)
	{
		B (ca, cb);//这里也是显示调用基类的构造函数,为什么不会报错呢?
		
		cout << "call C ()" << endl;
	}

private:
	int c;
};


int main ()
{
	C tmp (1, 2, 3);

	return 0;
}

运行结果如下: g++ 2.cpp ./a.out call A () call B () call A () call B () call C ()[/quote] 确实出现此问题,同时,我发现当类B在类C的初始化列表中初始化时,结果为

call A()
call B()
call C()
希望得到解释
todd_leftcode 2013-11-19
  • 打赏
  • 举报
回复
g++的错误信息还是比较明了的。 你声明了一个变量ca,这个变量遮住了参数里的ca变量,但这是不允许的,因为这两个ca在同一个作用域中。
A (ca);
表示声明一个A类型的变量 ca, 等价于
A ca;
A (ca + 0);
则表示用参数(ca+0)构造一个A类型的匿名对象。同理
B (ca, cb);
表示使用参数 ca, cb 构造一个匿名的B类对象。 这是由于编译器解析时语法优先级(我造的词)的原因造成的吧,看上去像是变更声明的换变量声明算,否则才考虑是不是是匿名变量构造(匿名变量用得少,所以优先级低吧) 无论如何,以上写法都不是调用基类或祖先类的构造函数的合法途径。首先要说,无论你写不写,基类的构造函数都会在任何一个本类声明的变量构造之前被调用,所以: 1. 基类的构造函数只能在初始化列表中调用 2. 无法隔代调用祖先类构造函数,因为这些函数已经被基类构造函数隐式调用过了,显示调用会引起重复构造,这是不允许的。
lm_whales 2013-11-19
  • 打赏
  • 举报
回复
引用 1 楼 go_and_see 的回复:

class C : public B 
{
public:
	C (int ca = 0, int cb = 0, int cc = 0)
		: B(ca, cb), c(cc)
	{
		//A (ca);	// 需要注释掉
		cout << "call C ()" << endl;
	}
private:
	int c;
};
//A (ca); // 需要注释掉, 因为不注释,没有这样的语法!! 这个 1)不是定义变量,函数。 2)也不是初始化表。 3)也不是其他合法语句。 这个是理所当然的错误。
luosimuer 2013-11-19
  • 打赏
  • 举报
回复
引用 8 楼 go_and_see 的回复:

#include "stdafx.h"
#include <iostream>
using namespace std;
 
class A
{
protected:
    A (int aa = 0) : a(aa)
    {
        cout << "call A ()" << endl;
    }
private:
    int a;
};
 
 
void func()
{
    A(abc);
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    func();
    return 0;
}
如果这么写就编译不过去了。
这个例子中构造函数被写成了protected的访问权限,这在外部是禁止访问的,而且构造函数一般都是写成public访问权限的啊。我的那个1.cpp中构造函数的权限确实是public的啊,2.cpp中构造函数的权限也是public的啊。我实在看不出有什么差异啊,但是结果却大相径庭啊~还是不大明白
边走边瞧 2013-11-19
  • 打赏
  • 举报
回复

#include "stdafx.h"
#include <iostream>
using namespace std;
 
class A
{
protected:
    A (int aa = 0) : a(aa)
    {
        cout << "call A ()" << endl;
    }
private:
    int a;
};
 
 
void func()
{
    A(abc);
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    func();
    return 0;
}
如果这么写就编译不过去了。
边走边瞧 2013-11-19
  • 打赏
  • 举报
回复
颜色怎么没效果了,还是直接帖代码吧:

void func()
{
010314C0  push        ebp  
010314C1  mov         ebp,esp 
010314C3  sub         esp,0CCh 
010314C9  push        ebx  
010314CA  push        esi  
010314CB  push        edi  
010314CC  lea         edi,[ebp-0CCh] 
010314D2  mov         ecx,33h 
010314D7  mov         eax,0CCCCCCCCh 
010314DC  rep stos    dword ptr es:[edi] 
A(abc);
010314DE  push        0    
010314E0  lea         ecx,[abc] 
010314E3  call        A::A (1031023h) 
}
边走边瞧 2013-11-19
  • 打赏
  • 举报
回复
引用 5 楼 jievisionvanish 的回复:
运行结果如下: g++ 2.cpp ./a.out call A () call B () call A () call B () call C ()
这个有点意思,刚开始没搞懂咋回事,看了汇编就明白了。为了简化,俺写个直观的例子,和你的不太一样。

#include "stdafx.h"
#include <iostream>
using namespace std;

class A
{
public:
	A (int aa = 0) : a(aa)
	{
		cout << "call A ()" << endl;
	}
private:
	int a;
};


void func()
{
	A(abc);
}



int _tmain(int argc, _TCHAR* argv[])
{
	func();
	return 0;
}
func()的汇编是:

void func()
{
010314C0  push        ebp  
010314C1  mov         ebp,esp 
010314C3  sub         esp,0CCh 
010314C9  push        ebx  
010314CA  push        esi  
010314CB  push        edi  
010314CC  lea         edi,[ebp-0CCh] 
010314D2  mov         ecx,33h 
010314D7  mov         eax,0CCCCCCCCh 
010314DC  rep stos    dword ptr es:[edi] 
	A(abc);
010314DE  push        0    
010314E0  lea         ecx,[abc] 
010314E3  call        A::A (1031023h) 
}
这个func函数实际上直接调用了class A的构造函数,参数是随机的(红色部分)。同样道理,你给的代码也是如此。
边走边瞧 2013-11-19
  • 打赏
  • 举报
回复

class C : public B 
{
public:
	C (int ca = 0, int cb = 0, int cc = 0)
		: B(ca, cb), c(cc)
	{
		//A (ca);	// 需要注释掉
		cout << "call C ()" << endl;
	}
private:
	int c;
};
luosimuer 2013-11-19
  • 打赏
  • 举报
回复
引用 4 楼 go_and_see 的回复:
[quote=引用 3 楼 jievisionvanish 的回复:] 我的这句A (ca);的本意是想显示调用从类A继承下来的类A的构造函数的,不知道为什么会有错呢?是不是不能在派生类中显示调用基类的构造函数呢?
因为你在B的出始化列表里已经写过A的构造,B会构造A,所以这个出错的语句没必要存在。[/quote] 现在很不解的问题是:我有2个代码,都是在派生类中显示调用基类的构造函数,其中1.cpp有错误,2.cpp却可以正常编译,不知道为什么?在派生类里面显示调用构造函数确实是很怪而且基本不会这么用(因为调用之后也并不会改变之前隐式调用或者用初始化成员列表去初始化的基类的对象的值---这点我用程序测试过)。不过我确实想知道这样写为什么会导致编译错误的原因,还请大家帮帮忙! 代码1.cpp 编译会报错

#include <iostream>

using namespace std;

class A
{
public:
	A (int aa = 0) : a(aa)
	{
		cout << "call A ()" << endl;
	}

private:
	int a;
};


class B : public A
{
public:
	B (int ba = 0, int bb = 0) : b(bb)
	{
		A (ba);//这里显示调用基类的构造函数 会报错 程序2.cpp中却不会 不知为何?
		cout << "call B ()" << endl;
	}

private:
	int b;
};


int main ()
{
	B tmp (1, 2);

	return 0;
}
编译之后报错: g++ 1.cpp 1.cpp: In constructor `B::B(int, int)': 1.cpp:24: error: declaration of 'A ba' shadows a parameter 代码2.cpp,可以正常编译和执行

#include <iostream>

using namespace std;

class A
{
public:
	A (int aa = 0) : a(aa)
	{
		cout << "call A ()" << endl;
	}

private:
	int a;
};


class B : public A
{
public:
	B (int ba = 0, int bb = 0) : A(ba), b(bb)
	{
		cout << "call B ()" << endl;
	}

private:
	int b;
};


class C : public B 
{
public:
	C (int ca = 0, int cb = 0, int cc = 0)
	  : c(cc)
	{
		B (ca, cb);//这里也是显示调用基类的构造函数,为什么不会报错呢?
		
		cout << "call C ()" << endl;
	}

private:
	int c;
};


int main ()
{
	C tmp (1, 2, 3);

	return 0;
}

运行结果如下: g++ 2.cpp ./a.out call A () call B () call A () call B () call C ()
边走边瞧 2013-11-19
  • 打赏
  • 举报
回复
引用 3 楼 jievisionvanish 的回复:
我的这句A (ca);的本意是想显示调用从类A继承下来的类A的构造函数的,不知道为什么会有错呢?是不是不能在派生类中显示调用基类的构造函数呢?
因为你在B的出始化列表里已经写过A的构造,B会构造A,所以这个出错的语句没必要存在。

64,670

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧