Ich habe die folgende Klasse in C ++:
class a {
const int b[2];
// other stuff follows
// and here's the constructor
a(void);
}
Die Frage ist, wie ich b in der Initialisierungsliste initialisiere, da ich es nicht im Hauptteil der Funktion des Konstruktors initialisieren kann, weil b ist const
.
Das funktioniert nicht:
a::a(void) :
b([2,3])
{
// other initialization stuff
}
Bearbeiten: Der Fall ist, wenn ich unterschiedliche Werte für b
unterschiedliche Instanzen haben kann, die Werte jedoch bekanntermaßen für die Lebensdauer der Instanz konstant sind.
c++
initialization
c++03
array-initialize
Nathan Fellman
quelle
quelle
std::array
, um einen Teil dieses Overheads zu vermeiden.Mit C ++ 11 hat sich die Antwort auf diese Frage geändert und Sie können tatsächlich Folgendes tun:
struct a { const int b[2]; // other bits follow // and here's the constructor a(); }; a::a() : b{2,3} { // other constructor work } int main() { a a; }
quelle
Dies ist im aktuellen Standard nicht möglich. Ich glaube, Sie können dies in C ++ 0x mithilfe von Initialisierungslisten tun ( weitere Informationen zu Initialisierungslisten und anderen nützlichen C ++ 0x-Funktionen finden Sie unter Ein kurzer Blick auf C ++ 0x von Bjarne Stroustrup).
quelle
std::vector
benutzt den Haufen. Meine Güte, was für eine Verschwendung, die nur für eineconst
Überprüfung der geistigen Gesundheit wäre. Der Punktstd::vector
ist dynamisches Wachstum zur Laufzeit, keine alte Syntaxprüfung, die zur Kompilierungszeit durchgeführt werden sollte. Wenn Sie nicht wachsen möchten, erstellen Sie eine Klasse, um ein normales Array zu verpacken.#include <stdio.h> template <class Type, size_t MaxLength> class ConstFixedSizeArrayFiller { private: size_t length; public: ConstFixedSizeArrayFiller() : length(0) { } virtual ~ConstFixedSizeArrayFiller() { } virtual void Fill(Type *array) = 0; protected: void add_element(Type *array, const Type & element) { if(length >= MaxLength) { // todo: throw more appropriate out-of-bounds exception throw 0; } array[length] = element; length++; } }; template <class Type, size_t Length> class ConstFixedSizeArray { private: Type array[Length]; public: explicit ConstFixedSizeArray( ConstFixedSizeArrayFiller<Type, Length> & filler ) { filler.Fill(array); } const Type *Array() const { return array; } size_t ArrayLength() const { return Length; } }; class a { private: class b_filler : public ConstFixedSizeArrayFiller<int, 2> { public: virtual ~b_filler() { } virtual void Fill(int *array) { add_element(array, 87); add_element(array, 96); } }; const ConstFixedSizeArray<int, 2> b; public: a(void) : b(b_filler()) { } void print_items() { size_t i; for(i = 0; i < b.ArrayLength(); i++) { printf("%d\n", b.Array()[i]); } } }; int main() { a x; x.print_items(); return 0; }
ConstFixedSizeArrayFiller
undConstFixedSizeArray
sind wiederverwendbar.Die erste ermöglicht die Überprüfung der Laufzeitgrenzen während der Initialisierung des Arrays (wie bei einem Vektor), die später
const
nach dieser Initialisierung erfolgen kann.Mit der zweiten Option kann das Array innerhalb eines anderen Objekts zugewiesen werden, das sich auf dem Heap oder einfach auf dem Stapel befinden kann, wenn sich dort das Objekt befindet. Es ist keine Zeitverschwendung, sich vom Haufen zu trennen. Es führt auch eine Konstantenprüfung zur Kompilierungszeit für das Array durch.
b_filler
ist eine winzige private Klasse, die die Initialisierungswerte bereitstellt. Die Größe des Arrays wird beim Kompilieren mit den Vorlagenargumenten überprüft, sodass keine Gefahr besteht, dass Grenzen überschritten werden.Ich bin sicher, es gibt exotischere Möglichkeiten, dies zu ändern. Dies ist ein erster Stich. Ich denke, Sie können jeden Mangel des Compilers mit Klassen so gut wie ausgleichen.
quelle
new
zu viel und noch mehr, wenn Sie zur Kompilierungszeit wissen, wie viel Sie benötigen. Beispielsweise ordnen einige Implementierungen von std :: vector seine Elemente in einem internen Puffer zu, anstatt sie zu verwendennew
, wodurch kleine Vektoren zum Erstellen / Zerstören recht billig sind.std::vector
und Arrays liefern genau den gleichen Code. Meine Güte.Nach dem ISO-Standard C ++ können Sie dies nicht tun. Wenn dies der Fall wäre, wäre die Syntax wahrscheinlich:
a::a(void) : b({2,3}) { // other initialization stuff }
Oder etwas in diese Richtung. Aus Ihrer Frage geht hervor, dass das, was Sie wollen, ein konstantes Klassenmitglied (auch bekannt als statisches Mitglied) ist, das das Array ist. Mit C ++ können Sie dies tun. Wie so:
#include <iostream> class A { public: A(); static const int a[2]; }; const int A::a[2] = {0, 1}; A::A() { } int main (int argc, char * const argv[]) { std::cout << "A::a => " << A::a[0] << ", " << A::a[1] << "\n"; return 0; }
Die Ausgabe ist:
A::a => 0, 1
Da dies ein statisches Klassenmitglied ist, ist es natürlich für jede Instanz der Klasse A gleich. Wenn dies nicht das ist, was Sie wollen, dh Sie möchten, dass jede Instanz von A unterschiedliche Elementwerte im Array a hat, das Sie erstellen der Fehler, zunächst zu versuchen, das Array const zu machen. Sie sollten dies einfach tun:
#include <iostream> class A { public: A(); int a[2]; }; A::A() { a[0] = 9; // or some calculation a[1] = 10; // or some calculation } int main (int argc, char * const argv[]) { A v; std::cout << "v.a => " << v.a[0] << ", " << v.a[1] << "\n"; return 0; }
quelle
Wo ich ein konstantes Array habe, wurde es immer als statisch ausgeführt. Wenn Sie das akzeptieren können, sollte dieser Code kompiliert und ausgeführt werden.
#include <stdio.h> #include <stdlib.h> class a { static const int b[2]; public: a(void) { for(int i = 0; i < 2; i++) { printf("b[%d] = [%d]\n", i, b[i]); } } }; const int a::b[2] = { 4, 2 }; int main(int argc, char **argv) { a foo; return 0; }
quelle
Sie können das nicht aus der Initialisierungsliste machen,
Schau dir das an:
http://www.cprogramming.com/tutorial/initialization-lists-c++.html
:) :)
quelle
Eine Lösung ohne Verwendung des Heaps mit
std::vector
ist die Verwendungboost::array
, obwohl Sie Array-Mitglieder nicht direkt im Konstruktor initialisieren können.#include <boost/array.hpp> const boost::array<int, 2> aa={ { 2, 3} }; class A { const boost::array<int, 2> b; A():b(aa){}; };
quelle
Wie wäre es mit der Emulation eines const-Arrays über eine Accessor-Funktion? Es ist nicht statisch (wie von Ihnen angefordert) und erfordert weder stl noch eine andere Bibliothek:
class a { int privateB[2]; public: a(int b0,b1) { privateB[0]=b0; privateB[1]=b1; } int b(const int idx) { return privateB[idx]; } }
Da a :: privateB privat ist, ist es außerhalb eines :: effektiv konstant, und Sie können ähnlich wie bei einem Array darauf zugreifen, z
a aobj(2,3); // initialize "constant array" b[] n = aobj.b(1); // read b[1] (write impossible from here)
Wenn Sie bereit sind, zwei Klassen zu verwenden, können Sie privateB zusätzlich vor Mitgliedsfunktionen schützen. Dies könnte durch Erben von a geschehen; aber ich glaube, ich bevorzuge John Harrisons comp.lang.c ++ - Beitrag mit einer const-Klasse.
quelle
Interessanterweise haben Sie in C # das Schlüsselwort const, das in die statische Konstante von C ++ übersetzt wird, im Gegensatz zu readonly, das nur bei Konstruktoren und Initialisierungen festgelegt werden kann, selbst durch Nichtkonstanten, z.
Ich bin damit einverstanden, wenn Sie ein vordefiniertes const-Array haben, können Sie es auch statisch machen. An diesem Punkt können Sie diese interessante Syntax verwenden:
//in header file class a{ static const int SIZE; static const char array[][10]; }; //in cpp file: const int a::SIZE = 5; const char array[SIZE][10] = {"hello", "cruel","world","goodbye", "!"};
Ich habe jedoch keinen Weg gefunden, um die Konstante '10' zu umgehen. Der Grund ist jedoch klar, es muss wissen, wie der Zugriff auf das Array durchgeführt wird. Eine mögliche Alternative ist die Verwendung von #define, aber ich mag diese Methode nicht und ich #undef am Ende des Headers, mit einem Kommentar, der dort auch bei CPP bearbeitet werden kann, falls sich etwas ändert.
quelle