在使用模板时,我遇到了一个需要使基类构造函数可以从继承类访问以创建对象以减少复制/粘贴操作。
我想通过using
关键字以与函数大小写相同的方式执行此操作,但这不起作用。
class A
{
public:
A(int val) {}
};
class B : public A
{
};
class C : public A
{
public:
C(const string &val) {}
};
class D : public A
{
public:
D(const string &val) {}
using A::A; // g++ error: A::A names constructor
};
void main()
{
B b(10); // Ok. (A::A constructor is not overlapped)
C c(10); // error: no matching function to call to 'C::C(int)'
}
所以我的问题:在声明了继承类中的新构造函数后,有没有办法导入基类构造函数?
或者只有一种方法可以声明新构造函数并从初始化列表中调用基础构造函数吗?
答案 0 :(得分:51)
是的,自C ++ 11以来:
struct B2 {
B2(int = 13, int = 42);
};
struct D2 : B2 {
using B2::B2;
// The set of inherited constructors is
// 1. B2(const B2&)
// 2. B2(B2&&)
// 3. B2(int = 13, int = 42)
// 4. B2(int = 13)
// 5. B2()
// D2 has the following constructors:
// 1. D2()
// 2. D2(const D2&)
// 3. D2(D2&&)
// 4. D2(int, int) <- inherited
// 5. D2(int) <- inherited
};
有关其他信息,请参阅http://en.cppreference.com/w/cpp/language/using_declaration
答案 1 :(得分:36)
首选初始化:
class C : public A
{
public:
C(const string &val) : A(anInt) {}
};
在C ++ 11中,您可以使用继承构造函数(具有示例D
中所示的语法)。
更新:自4.8版以来,GCC中提供了继承构造函数。
如果您没有发现初始化的吸引力(例如由于您的实际情况中的可能性数量),那么您可能会对某些TMP结构采用这种方法:
class A
{
public:
A() {}
virtual ~A() {}
void init(int) { std::cout << "A\n"; }
};
class B : public A
{
public:
B() : A() {}
void init(int) { std::cout << "B\n"; }
};
class C : public A
{
public:
C() : A() {}
void init(int) { std::cout << "C\n"; }
};
class D : public A
{
public:
D() : A() {}
using A::init;
void init(const std::string& s) { std::cout << "D -> " << s << "\n"; }
};
int main()
{
B b; b.init(10);
C c; c.init(10);
D d; d.init(10); d.init("a");
return 0;
}
答案 2 :(得分:9)
不,这不是它的完成方式。初始化基类的常规方法是在初始化列表中:
class A
{
public:
A(int val) {}
};
class B : public A
{
public:
B( int v) : A( v )
{
}
};
void main()
{
B b(10);
}
答案 3 :(得分:4)
您需要在每个派生类中声明构造函数,然后从初始化列表中调用基类构造函数:
class D : public A
{
public:
D(const string &val) : A(0) {}
D( int val ) : A( val ) {}
};
D variable1( "Hello" );
D variable2( 10 );
C ++ 11允许您使用在D的演绎中使用的A :: A语法,但刚才所有编译器都不支持C ++ 11特性,所以最好坚持使用旧的C ++方法将在您的代码将使用的所有编译器中实现此功能。
答案 4 :(得分:1)
以下是关于superclass constructor calling rules的一个很好的讨论。您始终希望在派生类构造函数之前调用基类构造函数,以便正确地形成对象。这就是使用此表单的原因
B( int v) : A( v )
{
}