我有一个没有默认构造函数的base_class
,我想定义它的矢量版本(称为derived_class
)。我知道我应该在我的base_class
构造函数中初始化derived_class
构造函数,但是下面的代码尝试初始化每行中大小为dim
和base_class(0,1)
的向量无法编译(它抱怨错误:'derived_class'的构造函数必须显式初始化没有默认构造函数的基类'base_class'),除非我将默认构造函数(注释行)添加到{{1 }}。我想念或误解了什么吗?有没有办法让它工作而不定义默认的base_class
构造函数?
base_class
更新:我知道在这个简单的例子中我完全可以避免继承,但请假设我确实需要继承实际练习,谢谢。
UPDATE2:正如@vishal所暗示,如果#include <iostream>
#include <vector>
class base_class
{
public:
//base_class(){};
base_class(double a, double b){a_=a; b_=b;}
private:
double a_, b_;
};
class derived_class : public base_class
{
public:
derived_class(int dim): vector_object(dim, base_class(0,1)){};
std::vector<base_class> print_vector_object() {return vector_object;}
private:
std::vector<base_class> vector_object;
};
int main()
{
int dim = 3;
derived_class abc(3);
std::cout << abc.print_vector_object().size() << std::endl;
return 0;
}
的构造函数被写为
derived_class
代码可以传递编译器。但我仍然不明白为什么我必须以这种方式初始化......
答案 0 :(得分:6)
好吧,既然你不想在基类中创建默认构造函数,你可以call base constructor by
:
derived_class(double a, double b, int dim) : base_class(a,b), vector_object(dim, base_class(0,1)) {};
答案 1 :(得分:1)
您的vector_object
是一个红色的鲱鱼,与问题无关,因为您可以使用以下代码进行验证,这也将使编译器抱怨缺少base_class
默认构造函数:
class derived_class : public base_class
{
public:
derived_class(int dim) {} // error, tries to use `base_class` default constructor,
// but there is none...
};
您必须提供默认构造函数或使用非默认构造函数。在derived_class
的每个实例中,都有一个base_class
子对象,并且必须以某种方式创建子对象。
误解的一个可能原因是,继承层次结构中的对象从上到下(从基础到初始化)被初始化。初看起来似乎不合逻辑,但是当derived_class
构造函数运行时,base_class
子对象必须已经存在。如果编译器无法提供此功能,则会出现错误。
因此,即使derived_class
构造函数指定 如何创建base_class
子对象,子对象的实际创建也会发生在创建derived_class
部分之前。
您问的是:
不应该在我的代码中初始化
base_class
对象吗?
您的代码必须初始化它,但事实并非如此。您不会在任何地方初始化它,并且默认初始化不起作用,因为基类没有默认构造函数。
有时,将继承视为一种特殊形式的组合(确实存在一些惊人的相似之处)是有帮助的。以下代码遇到的问题与您发布的问题相同:
class base_class
{
public:
//base_class(){};
base_class(double a, double b){a_=a; b_=b;}
private:
double a_, b_;
};
class derived_class // <--- no inheritance
{
public:
base_class my_base; // <--- member variable
derived_class(int dim) {};
};
您是否仍然认为derived_class
初始化base_class
对象?
另一个可能的误解来源是前面提到的红鲱鱼。你在说:
我只是不明白为什么我不能在矢量(...)中初始化它。
因为vector成员变量与base_class
子对象无关,或者与我的另一个示例中的public base_class
成员变量无关。矢量成员变量与其他任何变量之间没有神奇的关系。
再次使用原始代码,可以在内存中将完整的derived_class
对象描绘如下:
+-------------------+
| +---------------+ |
| | double | | <--- `base_class` sub-object
| | double | |
| +---------------+ |
+-------------------+ +--------+--------+--------+....
| std::vector ---------------> | double | double | double |
+-------------------+ | double | double | double |
+--------+--------+--------+....
^
|
|
a lot of other
`base_class` objects
向量管理的base_class
对象与<{1}}子对象完全无关,而该对象归属于类继承。
(图表有点过于简化,因为base_class
通常还会存储一些内部簿记数据,但这与此讨论无关。)
但是,无论如何,您的代码都没有令人信服的继承案例。那你为什么要继承呢?您可以这样做:
std::vector
答案 2 :(得分:0)
您确定derived_class
- 对象是base_class
- 对象和拥有vector
个base_class
- 对象吗?< / p>
我认为,您实际上只需要vector
个base_class
个对象。如果确实如此,请勿从derived_class
派生base_class
。实际上,这是编译器消息的来源。它告诉您,您必须初始化base_class
对象的derived_class
方面。
所以这是我的解决方案(注意,代码未经测试,可能包含一些错误):
#include <iostream>
#include <vector>
class base_class
{
public:
// c++11 allows you to explicitly delete the default constructor.
base_class() = delete;
base_class(double a, double b):
a_{a}, b_{b} // <- prefer initializers over constructor body
{};
private:
double a_;
double b_;
};
class derived_class // <- this name is wrong now of course; change it.
{
public:
derived_class(int dim):
// better initialize doubles with float syntax, not int.
vector_object{dim, base_class{0.0, 1.0}}
{};
// Note: this will copy the whole vector on return.
// are you sure, that is what you really want?
auto print_vector_object() -> std::vector<base_class> {
return vector_object;
};
private:
std::vector<base_class> vector_object;
};
int main(int, char**)
{
// int dim = 3; <- this is useless, you never use dim.
auto abc = derived_class{3};
std::cout << abc.print_vector_object().size() << std::endl;
return 0;
}
注意:我的代码是C ++ 11。
答案 3 :(得分:0)
我稍微重写了你的课程
#include <iostream>
#include <vector>
class base_class {
private:
double a_, b_;
public:
//base_class(){};
base_class(double a, double b ) : a_(a), b_(b) {}
virtual ~base_class();
};
class derived_class : public base_class {
private:
std::vector<base_class> vector_object;
public:
explicit derived_class( int dim ) : base_class( 0, 1 ) {
vector_object.push_back( static_cast<base_class>( *this ) );
}
~derived_class();
std::vector<base_class> get_vector_object() const { return vector_object; }
};
int main() {
int dim = 3;
derived_class abc(3);
std::cout << abc.get_vector_object().size() << std::endl;
return 0;
}
这正确地构建和编译。我做了一些更改:我使用了构造函数成员初始化列表(如果适用),我已经为您的基类添加了一个虚拟析构函数;你从基类继承的任何时候都应该有一个虚拟析构函数,我将所有私有成员变量移到了类的顶部而不是在底部,我使用explicit关键字为derived_class构造函数添加了前缀,因为你只有一个参数传递给它,我已经将derived_class构造函数更改为在其成员的初始化列表中使用base_class构造函数,并使用push_back()方法在构造函数中填充其成员变量向量,并将取消引用此指针静态地转换为base_class类型,我也将你的print_vector_object方法更改为get_vector_object,因为它没有打印任何内容,只返回类中的成员向量。我还将此方法声明为const,因此它不会更改类,因为您只是检索它。我唯一的问题是derived_class中的int
参数是做什么的?它不会在任何地方使用,也没有成员变量来存储它。
此处派生类的此部分
公共: derived_class(int dim):vector_object(dim,base_class(0,1)){};
你声明你的构造函数对我没有任何意义。
您似乎正在尝试使用成员初始化列表来填充您的向量成员变量,方法是传入派生类传入的参数并将构造函数调用到基类,值为{0,1} 。这不会像你期望的那样工作。首先必须构造Base Class对象,它是此派生类的子对象,而不是构造函数的函数范围,然后您可以填充成员向量。
您所拥有的内容会导致问题,因为您没有提供可用于构建派生类型的默认构造函数。由于我可以收集你所显示的内容以及它所显示的内容,因此您希望在调用派生构造函数时将base_class初始化为{0,1};如果是这种情况,你可以调用你实现的base_class构造函数,并在构造函数中传递{0,1},同时尝试构造派生类型。这将允许从构造base_class以来正确构造derived_class。现在您可以开始构建派生类型,看起来您希望将构造的base_class保存到派生类型向量成员变量中。这就是我在构造函数中而不是在初始化列表中执行此操作的原因,并且我将使用解除引用的this指针静态转换回基类型的派生类型的实例push_back。此外,当我在主函数中设置一个断点时,你试图打印它的大小,然后我看看derived_class的成员变量,它填充了1个对象,其值为a = 0和b = 1。能够打印这些你必须添加公共get方法来返回每个变量。此外,如果不需要派生类中的int参数,则可以将其与explicit关键字一起删除。你也可以为派生类型实现第二个构造函数,它接受两个双精度,就像基数一样,并将这些参数从derived_class构造函数传递给base_class构造函数,如下所示:
public:
derived_class( double a, double b ) : base_class( a, b ) {
vector_object.push_back( static_cast<base_class>( *this ) );
}
我将演示一个基本和两个派生类的简单示例,其中第一个实例必须在构造时设置值,而第二个实例必须使用自己的构造函数,其中没有在基础中定义的默认构造函数类。
class Base {
private:
double x_, y_, z_;
public:
Base( double x, double y, double z );
virtual ~Base();
};
Base::Base() :
x_( x ), y_( x ), z_( z ) {
}
Base::~Base() {
}
class DerivedA : public Base {
private:
int value_;
public:
explicit DerivedA( int value );
~DerivedA();
};
// In This Case A Must Set The Values In The Constructor Itself: I'll Just
// Set Them To (0, 0, 0) To Keep It Simple
DerivedA::DerivedA( int value ) :
Base( 0, 0, 0 ),
value_( value ) {
}
DerivedA::~DerivedA() {
}
class DerivedB : public Base {
private:
int value_;
public:
DerivedB( int value, double x, double y, double z );
~DerivedB();
};
// In This Case B Doesn't Have To Know What Is Needed To Construct Base
// Since Its Constructor Expects Values From Its Caller And They Can
// Be Passed Off To The Base Class Constructor
DerivedB::DerivedB( int value, double x, double y, double z ) :
Base( x, y, z ),
value_( value ) {
}
DerivedB::~DerivedB() {
}
请告诉我这是否可以帮助您!