Pavel Minayev
Posted in reply to Brian Folan
| "Brian Folan" <99541157@itb.ie> wrote in message news:a62kuq$2tgd$1@digitaldaemon.com...
> i only program in C in college, with limited c++ exposure, and i cant find the difference between C++ and D :(
I recommend you to read the "Overview" and "Converting C++ to D" sections of the D manual for detailed explanations, but here are the most important (IMO) features you should be aware of:
- Objects are never instantiated on stack. In C++, this is a common
practice. In D, you always use operator new to create an object.
Variables of type "object" are actually references to objects, and
not objects themselves:
/* C++ */
class Foo { ... }
Foo bar; // bar is an instance of Foo
Foo* baz; // baz is a pointer to instance of Foo
/* D */
class Foo { ... }
Foo bar; // bar is a reference (strict pointer) to instance of Foo
Foo* baz; // baz is a pointer to reference to instance of Foo
- In C++, classes and structs are pretty much the same. In D, the "class"
keyword declares what is called class in C++, and D "struct" has the
abilities of C (not C++) structure.
- C++ program can be divided into parts by writing several .cpp files, and
providing an interface header .h file for each; this mechanism relies
on preprocessor to #include interface files. Namespaces are separately
provided by the namespace statement. D divides programs into modules,
each .d file is a separate module with its own namespace; you import
modules with the import directive, and there is no need for separate
interface files.
- C++ requires global types, constants, variables, functions to be declared
before they are used, and introduces a special syntax to provide forward
references. In D you can use function declared in your module from any
point of that module:
/* C++ */
void bar(); // forward declaration needed
void foo() { bar(); }
void bar() { foo(); }
/* D */
void foo() { bar(); } // bar() is already visible!
void bar() { foo(); }
- In C++, class members are private by default. In D, they are public
by default. Also, you cannot use the public/private/protected specifier
when inheriting from base class - it's always public:
/* C++ */
class Foo: public Bar { ... }
/* D */
class Foo: Bar { ... }
- In C++, bodies of member functions can be defined outside class
definition,
and it is the prefferd way. This is not possible (nor it is needed) in D:
/* C++ */
class Foo
{
void bar();
}
void Foo::bar() { ... }
/* D */
class Foo
{
void bar() { ... }
}
- C++ has three distinct resolution operators: "." (direct member access), "->" (indirect member access), and "::" (static member access). C++ also uses "::" to access member of the base class, or namespace. These all are replaced by a single "." in D, and compiler determines the exact meaning depending on the context:
/* C++ */
struct Foo { int n; }
Foo bar;
Foo* baz;
bar.n = 1; baz->n = 1;
/* D */
struct Foo { int n; }
Foo bar;
Foo* baz;
bar.n = 1; baz.n = 1;
- Constructor/destructor semantics are different:
/* C++ */
class Foo
{
Foo() { ... } // constructor
~Foo() { ... } // destructor
}
/* D */
class Foo
{
this() { ... } // constructor
~this() { ... } // destructor
}
- To call methods of base class, you use the pseudo-variable "super":
/* C++ */
class Foo
{
public: void baz() { ... }
}
class Bar: public Foo
{
public: void baz() { Foo::baz(); /* call version of base class */ }
}
/* D */
class Foo
{
void baz() { ... }
}
class Bar: Foo
{
void baz() { super.baz(); /* call version of base class */ }
}
- In C++, you have to call constructor of the base class (or it is
done for you implicitly) at the beginning of your constructor using
a weird syntax. Also, you cannot call one constructor of your class
from another in that class. In D, constructors are just functions,
and are called as such:
/* C++ */
class Foo
{
public:
Foo() { default_ctor(); }
Foo(int n) { default_ctor(); ... }
private:
void default_ctor() { /* does what needs to be done in any case */ }
}
class Bar: public Foo
{
public: Bar(int n): Foo(n) { ... }
}
/* D */
class Foo
{
this() { /* does what needs to be done in any case */ }
this(int n) { this(); ... }
}
class Bar: Foo
{
this(int n) { super(n); ... }
}
- D syntax for array and pointer declarations is a bit different from C++ one:
/* C++ */
int foo, bar[5]; // foo is int, bar is array of ints
int* foo, bar; // foo is pointer to int, bar is int
/* D */
int[5] foo, bar; // both foo and bar are arrays of ints
int* foo, bar; // both foo and bar are pointers to int
- D types are a bit different from those of C++. Here's the equivalence
table
for a typical Win32 C++ compiler:
D -> 32-bit C++
char -> char
byte -> signed char
ubyte -> unsigned char
short -> signed short
ushort -> unsigned short
int -> signed int, signed long
uint -> unsigned int, unsigned long
long -> N/A (64-bit signed int, signed long long in GCC)
ulong -> N/A (64-bit unsigned int, unsigned long long in GCC)
float -> float
double -> double
extended -> long double
complex -> std::complex
imaginary -> N/A
- D provides built-in dynamic arrays, with functionality similar
to the one provided by std::vector class from C++ STL; the syntax
is much simpler, however:
/* C++ */
vector<int> foo; // dynamic arrays of ints
foo.push_back(1); // append 1 to the end of the array
foo[0] = 2; // element access
// iteration
for (int i = 0; i < foo.size(); i++)
foo[i] = 666;
/* D++ */
int[] foo; // dynamic array of ints
foo ~= 1; // append 1 to the end of the arrat
foo[0] = 2; // element access
// iteration
for (int i = 0; i < foo.length; i++)
foo[i] = 666;
- Strings are represented by dynamic arrays of chars, rather than
by pointers to null-terminated char sequences or std::string
C++ STL class:
/* C++ */
string foo, bar, baz;
foo = "Hello, ";
bar = "world!";
baz = foo + bar; // concatenate with +
baz += "\n"; // append with +=
/* D */
char[] foo, bar, baz;
foo = "Hello, ";
bar = "world!";
baz = foo ~ bar; // concatenate with ~
baz ~= "\n"; // append with ~=
- Everything is garbage-collected. That is, everything allocated
by operator new, be it an object or a dynamic array, gets freed
automatically, you don't have to use operator delete. This allows
you to write code that is unsafe (and thus considered "bad") in
C++, but perfectly legal in D:
/* bad C++, but legal D */
int* foo(int n)
{
int* result;
result = new int[n];
return result;
}
void main()
{
int* array = foo(5);
...
return 0; // forgot to delete array! OK in D, bad thing in C++
}
Oh, damn, I've tired of typing. =) There are SO many differences...
I haven't mentioned array slicing, design by contract (the "Contracts"
section in the D reference is a MUST READ!), interfaces, type complex,
standard library, and many other things. Once again, the best idea
is to read the entire D reference document, everything's there...
|