C programmers How to use D programming each experienced C programmer has accumulated a series of habits and technologies, which is almost the next day. Sometimes, when learning a new language, these habits will make people can't see the secondary price of the new language because it is too comfortable. So some commonly used C technology is collected, and how the same tasks are completed in D.
See also: How can the programmer uses D programming
Define Constructor Base Class Initialization Comparison Structure Creating New TypeDef Item Operator Overloaded Name Space Using Declaration RAII (Resource Getting Initialization) Properties Recursive Template
Define constructor
C mode constructor is the same name:
Class foo
{
Foo (int X);
}
D method constructor definition with this keyword:
Class foo
{
THIS (INT X) {}
}
Base class initialization
C method base class constructor is called by parameter initialization column syntax.
Class a {a () {...}};
Class B: a
{
B (int x)
: A () // Call the base class constructor
{...
}
}
D method base class constructor is called by Super Keyword:
Class a {this () {...}}
Class B: a
{
THIS (INT X)
{...
Super (); // Call the base class constructor
...
}
}
D method is better than that of C is to invoke the base class constructor anywhere in the derived class constructor. D can also make a constructor call another constructor:
Class A
{INT A;
INT B;
THIS () = 7; b = foo ();}
THIS (INT X)
{
THIS ();
A = x;
}
}
You can also initialize the member before calling the constructor, so the above example is equivalent to:
Class A
{INT A = 7;
INT B;
THIS () {b = foo ();
THIS (INT X)
{
THIS ();
A = x;
}
}
Compare structure
C way although C defines the assignment between the structure in simple and convenient way:
Struct a x, y;
...
X = Y;
But this does not apply to the comparison between the structure. Therefore, if it is necessary to compare equivalence between the two structural examples:
#include
Struct a x, y;
Inline Bool Operator == (Const A & X, Const A & Y)
{
Return (Memcmp (& X, & Y, SIZEOF (STRUCT A)) == 0);
}
...
IF (x == y)
...
Note For each structure that needs to be compared, the operator is overloaded, and the operator's overload will abandon all languages provided. There is another problem in the C way, it does not check (x == Y) what truly happens, you have to look at each overloaded Operator == () to determine what they have done.
If you use Memcmp () in Operator == (), it also causes potential and ugly bugs. Due to alignment, the memory distribution of the structure is not continuous, there may be "holes". C does not guarantee that the values in the alignment holes are determined, so two structural examples may have exactly the same structural members, but because of different garbage in the hole. To solve this problem, Operator == () can be implemented as a member of Memberwise. Unfortunately, this is unreliable because (1) If a member is added to the structural definition, the programmer may forget to add it to Operator == (), (2) NAN values for floating point numbers For example, even if they are relatively equal, the results of the comparison are not.
There is no robust solution in C .
D 's way D method is obvious and directly:
A x, y;
...
IF (x == y)
...
Create a new TypeDef type
The C way TypeDef is weak in C , that is, they don't really introduce a new type. The compiler does not distinguish the type of typedef and its underlying.
#define handle_init (Handle) (- 1))
Typedef void * handle;
Void foo (void *);
Void bar (Handle);
Handle h = handle_init;
Foo (h); // Unrecounted code error
BAR (h); // ok
The C solution is to create a Dummy structure. The only purpose of this structure is to get the true new type of types of types and overloaded capabilities.
#define handle_init ((void *) (- 1))
Struct Handle
{void * PTR;
Handle () {ptr = Handle_init;} // default initializer
Handle (INT I) {PTR = (Void *) i;}
Operator void * () {return ptr;} // converness to underlying type
}
Void bar (Handle);
Handle H;
Bar (h);
H = func ();
IF (h! = handle_init)
...
D method does not require the usual configuration. Just write this:
Typedef void * Handle = CAST (VOID *) - 1;
Void bar (Handle);
Handle H;
Bar (h);
H = func ();
IF (h! = handle.init)
...
Note that a default initial value can be provided to TypeDef as a new type of initial value.
Friendly
C 's way sometimes two types of relationships are very close, they are not inheritance, but they need to access each other's private members. Use this in C
Friend declaration:
Class A
{
Private:
Int a;
PUBLIC:
INT foo (b * j);
Friend class b;
Friend Int ABC (A *);
}
Class B
{
Private:
INT B;
PUBLIC:
Int bar (a * j);
Friend class a;
}
INT A:: foo (b * j) {return j-> b;}
Int b :: bar (a * j) {return j-> a;}
INT ABC (A * P) {RETURN P-> a;}
D. In D, the class of hiddenly with friend access rights in the same module. This makes sense, because the relationship is in the same module, so it is implicitly imparted by other category visits located in the same module: Elegant:
Module X;
Class A
{
Private:
Static Int A;
PUBLIC:
INT foo (b j) {return j.b;}
}
Class B
{
Private:
Static int b;
PUBLIC:
Int bar (a j) {returnj.a;}
}
INT ABC (A P) {Return P.a;}
The Private feature prohibits access to members from other modules.
Operator overload
C mode assumes that there is a structure representing a new arithmetic type, which is overloaded to make it compared to the integer:
Struct a
{
INT Operator <(INT I);
INT operator <= (int i);
INT Operator> (INT I);
INT Operator> = (int i);
}
Int Operator <(INT I, A & A) {RETURN A> I;}
INT Operator <= (int I, A & a) {RETURN A> = i;}
INT Operator> (INT I, A & A) {Return a
INT Operator> = (int I, A & a) {RETURN A <= i;}
All 8 functions are unable.
D's way D recognizes that the comparison operator is associated with each other. So only one function is required:
Struct a
{
INT OPCMP (INT I);
}
Compiler according to
The OPCMP function automatically explains the <, <=,> and> = operator, and handling the left operating case is not an object reference.
Similar to such a sensible rule is also suitable for other operators overload, which makes the operator overload in D is not as cumbersome and easy to errors like in C . Only less code is required, you can reach the same effect.
Name space Using statement
C way C
Using statement is used to introduce the name into the current scope from a namespace scope:
Namespace foo
{
INT X;
}
Using foo :: x;
The way D of D is used by modules instead of namespaces and #include files, with alias declarations instead of USING statement:
---- Module foo.d ------
Module foo;
INT X;
---- Another Module ----
IMPORT FOO;
Alias foo.x;
Alias is much flexible than simple Using statements. Alias can be used to rename symbols, reference template members, reference nested types, etc.
RAII (resource acquisition is initialized)
The C method is in C , resources such as memory, etc., it requires explicit processing. Because the destructor is automatically called when exiting the current scope, the RAII can achieve the resource release code to put the resource release code in the decimal function:
Class file
{Handle * h;
~ File ()
{
H-> Release ();
}
D 's way Most resource release problems are simple trace and release memory. This is done automatically by the garbage collection program. In addition to memory, the most popular resources are used for semaphones, and they are available in D.
SYNCHRONIZED declaration and statement automatic management.
The remaining situations can be handled by AUTO class. When the AUTO class exits its scope, they call their destructor.
Auto Class File
{Handle H;
~ this ()
{
H.RELEASE ();
}
}
Void test ()
{
IF (...)
{Auto file f = new file ();
...
} // f. ~ this () starts running at the anti-parentheses, even because of the throwing an exception to exit the role
}
Attributes
C way people often define a domain while providing it to object-oriented GET and SET functions:
Class ABC
{
PUBLIC:
Void setProperty (int newproperty) {property = newproperty;
INT getProperty () {return property;}
Private:
INT Property;
}
ABC A;
A.SETPROPERTY (3);
INT x = a.getProperty ();
All of this is just a number of times the keystroke is added, and the code will not be easy to read because of getProperty () and setProperty () calls.
D method properties can use normal domain syntax GET and SET, then GET and SET will be replaced by the compiler method call.
Class ABC
{
Void Property (int newproperty) {myprop = newproperty;} // set
INT property () {return myprop;} // Get
Private:
INT myprop;
}
when using it:
ABC A;
A.Property = 3; // Is equivalent to A.Property (3)
INT x = a.property; // Equivalent to int x = a.property ()
Therefore, attributes in D can be seen as a simple domain name. At the beginning, the property can be just a simple domain name, but if you later change the read and set behavior to function call, you only need to change the definition of the class. This avoids the detection of lengthy code when defining GET and SET, just to "Beware" The derived class may have to be overloaded. This is also a way to define interface classes. These classes have no data fields, which seem to be actually working in syntax.
Regenerative template
The C method is a high-level way of using the template to expand them, and the specialization is detrimental to termination. The template used to calculate the stage may be like this:
Template
{
PUBLIC:
Enum {result = n * factorial
}
Template <> Class Factorial <1>
{
PUBLIC:
ENUM {result = 1};
}
Void test ()
{
Printf ("% D / N", Factorial <4> :: result); // Print 24
}
The version of D is similar, but simple, using the ability to upgrade a single template to the peripheral name Space: Template Factorial (int N)
{
Enum {factory = n * .factorial! (N-1)}
}
Template Factorial (Int N: 1)
{
ENUM {Factorial = 1}
}
Void test ()
{
Printf ("% D / N", Factorial! (4)); // Print 24
}