Lihat tautan ini: https: //msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(C4503)&rd=true Disarankan untuk menulis:

// C4503b.cpp  
// compile with: /W1 /EHsc /c  
#include <string>  
#include <map>  

class Field{};  
struct Screen2 {  
   std::map<std::string, Field> Element;  
};  

struct WebApp2 {  
   std::map<std::string, Screen2> Element;  
};  

struct WebAppTest2 {  
   std::map<std::string, WebApp2> Element;  
};  

struct Hello2 {  
   std::map<std::string, WebAppTest2> Element;  
};  

Hello2 MyWAT2;  

Dari pada

// C4503.cpp  
// compile with: /W1 /EHsc /c  
// C4503 expected  
#include <string>  
#include <map>  

class Field{};  

typedef std::map<std::string, Field> Screen;  
typedef std::map<std::string, Screen> WebApp;  
typedef std::map<std::string, WebApp> WebAppTest;  
typedef std::map<std::string, WebAppTest> Hello;  
Hello MyWAT; 

Tetapi kode-kode itu tidak setara dengan typedefs Hello adalah std::map sedangkan dengan structs itu hanya sebuah struct yang memiliki bidang yang merupakan map yang berarti saya tidak dapat menggunakannya secara bergantian. Bisakah seseorang menjelaskan triknya?

3
Narek 7 Desember 2016, 16:14

4 jawaban

Jawaban Terbaik

Anda benar, Anda tidak dapat menggunakannya secara bergantian. Faktanya, Microsoft menyarankan Anda untuk melakukannya untuk mengatasi kesulitan teknis dari ujungnya: mereka tidak dapat (atau mengalami kesulitan untuk) menangani nama yang rusak lebih dari 4096 byte.

Dalam kebanyakan kasus, typedef akan menjadi solusi yang lebih baik daripada agregasi, saya percaya.

Tetapi karena kompiler Anda agak terbatas, Anda mungkin terjebak dengan peretasan mereka.

4
YSC 7 Desember 2016, 13:23

typedef tidak mendeklarasikan tipe baru, itu hanya alias. Dan jika Anda meneruskan-deklarasikan typedef, saat kompilator melihat definisi typedef, itu memberi Anda kesalahan:

// a.hpp
class Screen;

class any_class_using_screen {};

// a.cpp
#include "a.hpp"

typedef std::map<std::string, Field> Screen; // Error.

Menggunakan warisan bahkan sederhana memungkinkan Anda untuk menggunakan nama kustom Anda untuk jenis lain:

class Screen : public std::map<std::string, Field>
{};

Ingat bahwa pewarisan sederhana tanpa anggota tambahan tidak menyebabkan memori atau overhead waktu. Itu seefisien typedef, dengan keuntungan bahwa itu adalah tipe baru.

Karena std::map<...> tidak memiliki destruktor virtual, Anda tentu saja tidak dapat menggunakan pola "pointer to base class" seperti biasa. Pemilik instance Screen (orang yang membuat instance screen), jika ia tinggal di heap dan harus dimusnahkan, harus dimusnahkan dari pointer ke kelas turunan:

template<class K, class V>
void f(std::map<K, V> const* map); // Do something

int main()
{
    Screen* s = new Screen;
    f(s); // Ok
    delete s; // OK, deleting from derivate class
}

@PeterA.Scheneider menyarankan bahwa, sejauh kelas turunan tidak memiliki anggota tambahan, tidak ada yang terjadi, dan Anda dapat memanggil destruktor dari pointer ke kelas turunan. Tetapi, theoretically, tanpa destruktor virtual, Anda merusak instance kelas dasar (hanya kehidupan kelas dasar yang mencapai akhir), dan instance kelas turunan masih hidup dengan basis mati, memiliki objek yang rusak. Dari sudut pandang praktis, saya pikir objek dirusak dengan benar, tetapi bagaimanapun saya tidak tahu apakah itu dapat menyebabkan perilaku yang tidak terdefinisi.

Standar harus diperiksa untuk memastikan.

Selain itu, mungkin ada masalah penyelarasan dengan pendekatan penghancuran itu, dari penunjuk kelas dasar, objek turunan tanpa anggota tambahan.

Jika kelas dasar tidak memiliki destruktor virtual, lakukan pewarisan tanpa "niat polimorfik", dan hancurkan selalu dari kelas yang paling diturunkan.

0
Peregring-lk 7 Desember 2016, 13:43

solusi yang diberikan tidak dimaksudkan sebagai pengganti yang setara dari pereproduksi, melainkan sebagai cara mungkin untuk mengurangi panjang dekorasi simbol yang diekspor.

Anda dapat memverifikasi dengan objdump /symbols objfile.obj sederhana bahwa panjang simbol yang dihias dengan menggunakan typedefs jauh lebih panjang daripada rekan-rekan serupa mereka yang dipecah menjadi struct (kompiler Microsoft secara historis menggunakan mangling nama berpemilik skema).

0
Marco A. 7 Desember 2016, 13:36

Jika Anda menginginkan solusi yang memenuhi tujuan untuk membedakan nama (rusak, mungkin terpotong), tetapi tanpa kerugian dari lapisan penamaan tambahan, Anda dapat menggunakan warisan:

class Screen : public std::map<std::string, Field>
{
    // forward constructors here
};
3
John Zwinck 7 Desember 2016, 13:22