Заранее спасибо.
Я видел эти коды в каком-то реальном проекте. Я просто упростил их, чтобы выразить свою проблему здесь. Базовый класс ставит этот указатель на вектор (VEC) в своем конструкторе. Используя этот трюк, мы можем управлять динамическим связыванием, чтобы вызывать метод производных классов снаружи (в основной функции). Ключевой момент — поместить определение вектора в Bash.h, а объявление в main.cpp.
Мой вопрос, выход не то, что я хочу. Почему vec инициализируется и используется в одной единице перевода (base.c, мы видим размер 1), затем в других единицах перевода (main.c, мы видим, что размер становится 0), инициализируется и очищается снова? Я хочу знать порядок инициализации по различным единицам перевода. Кажется, что сначала Derive :: dInstance, а затем vec, но почему?
Base.h
#ifndef BASE_H
#define BASE_h
#include<iostream>
#include<vector>
using namespace std;
class Base{
public:
Base();
virtual void speak();
};
#endif
Base.cpp
#include"Base.h"
vector<Base*> vec;
Base::Base() {
vec.push_back(this);
cout << "Base's constructor" << endl;
cout << "Base() vector size: " << vec.size() << endl;**
}
void Base::speak() {
cout << "I am Base" << endl;
}
Derive.h
#ifndef DERIVE_H
#define DERIVE_h
#include<iostream>
#include"Base.h"
class Derive: public Base {
public:
Derive();
virtual void speak();
static Derive dInstance;
};
#endif
Derive.cpp
#include "Derive.h"
// static member definition
Derive Derive::dInstance;
Derive::Derive() {
cout << "Derived's construtor" << endl;**
}
void Derive::speak() {
cout << "I am Derived" << endl;
}
main.cpp
#include<iostream>
#include"Base.h"
using namespace std;
extern vector<Base*> vec;
int main(int argc, char *argv[]) {
cout << "vector size: " << vec.size() << endl;
for(vector<Base*>::iterator iter = vec.begin(); iter != vec.begin(); iter++) {
(*iter)->speak();
}
}
Выход:
Конструктор базы База () векторный размер: 1 Производный конструктор main () векторный размер: 0
Это «static
Порядок инициализации фиаско ».
Порядок инициализации между переводческие единицы из static
(или глобальные) переменные не определены. Так что подумайте, что произойдет, если Derived.cpp
файл инициализируется раньше Base.cpp
затем вы добавляете к вектору, который не инициализирован (построен), что приводит к неопределенное поведение, затем вектор инициализируется.
Во-первых, не существует правила для порядка инициализации по различным единицам перевода.
И глобальная переменная и глобальная статическая переменная будут инициализированы перед основной функцией. Локальная статическая переменная, принадлежащая функции FuncA (), будет инициализирована при первом вызове FuncA ().