Тривиальный пример с Животным и Собакой: Вы зеркально отражаете vtable механизм C++ (в основном так или иначе). Вы также разделяете выделение и инстанцирование (Animal_Alloc, Animal_New), таким образом, мы не называем malloc () многократно. Мы должны также явно раздать this
указатель.
, Если необходимо было сделать невиртуальные функции, это - trival. Вы просто не добавляете их к vtable и статическим функциям, не требуют this
указатель. Множественное наследование обычно требует, чтобы несколько vtables разрешили неоднозначности.
кроме того, необходимо быть в состоянии использовать setjmp/longjmp, чтобы сделать обработку исключений.
struct Animal_Vtable{
typedef void (*Walk_Fun)(struct Animal *a_This);
typedef struct Animal * (*Dtor_Fun)(struct Animal *a_This);
Walk_Fun Walk;
Dtor_Fun Dtor;
};
struct Animal{
Animal_Vtable vtable;
char *Name;
};
struct Dog{
Animal_Vtable vtable;
char *Name; // Mirror member variables for easy access
char *Type;
};
void Animal_Walk(struct Animal *a_This){
printf("Animal (%s) walking\n", a_This->Name);
}
struct Animal* Animal_Dtor(struct Animal *a_This){
printf("animal::dtor\n");
return a_This;
}
Animal *Animal_Alloc(){
return (Animal*)malloc(sizeof(Animal));
}
Animal *Animal_New(Animal *a_Animal){
a_Animal->vtable.Walk = Animal_Walk;
a_Animal->vtable.Dtor = Animal_Dtor;
a_Animal->Name = "Anonymous";
return a_Animal;
}
void Animal_Free(Animal *a_This){
a_This->vtable.Dtor(a_This);
free(a_This);
}
void Dog_Walk(struct Dog *a_This){
printf("Dog walking %s (%s)\n", a_This->Type, a_This->Name);
}
Dog* Dog_Dtor(struct Dog *a_This){
// Explicit call to parent destructor
Animal_Dtor((Animal*)a_This);
printf("dog::dtor\n");
return a_This;
}
Dog *Dog_Alloc(){
return (Dog*)malloc(sizeof(Dog));
}
Dog *Dog_New(Dog *a_Dog){
// Explict call to parent constructor
Animal_New((Animal*)a_Dog);
a_Dog->Type = "Dog type";
a_Dog->vtable.Walk = (Animal_Vtable::Walk_Fun) Dog_Walk;
a_Dog->vtable.Dtor = (Animal_Vtable::Dtor_Fun) Dog_Dtor;
return a_Dog;
}
int main(int argc, char **argv){
/*
Base class:
Animal *a_Animal = Animal_New(Animal_Alloc());
*/
Animal *a_Animal = (Animal*)Dog_New(Dog_Alloc());
a_Animal->vtable.Walk(a_Animal);
Animal_Free(a_Animal);
}
пз. Это тестируется на компиляторе C++, но должно быть легко заставить его работать над компилятором C.
Я бы использовал фабричный метод в частичном классе для DataContext. Имейте в виду, что строка подключения для DataContext отличается от обычной строки подключения ADO.NET.
Код .... Я никогда не использовал VB.NET, но это должно быть примерно так:
Partial Public Class MyDataContext
' GetConnectionString code here
'
Public Shared Function Create() As MyDataContext
Return New MyDataContext(GetConnectionString())
End Function
End Class
Используйте что вместо использования New MyDataContext () .
В качестве альтернативы вы можете вызывать
dc = New MyDataContext(GetConnectionString())
везде, где вы получаете новый экземпляр, но я предпочитаю фабричный метод.
Основная идея такая же, как и ваш подкласс, но без запутанного дополнительного имени класса. Частичные классы очень полезны, когда дело касается Entity Framework (или любых инструментов генерации кода). Вы можете добавить методы бизнес-логики в классы, созданные Entity Framework и т. Д.