Програмен език C++
Част 33

 Едноаргументният конструктор
(The One-Argument Constructor)
.
(съдържание)

Едноаргументният конструктор играе специална роля в обектно-ориентираното програмиране. Той може да се използва за преобразуване на обект от един клас в обект от друг, затова другото име за този тип конструктори е преобразуваща функция (conversion function).
.
1. Едноаргументен конструктор. В предишната лекция 32 в т. 3 бяха написани два (!) едноаргументни конструктора в дадената примерна програма. Това бяха следните два конструктора (от общо четири):

  richman(int m) : name("Angel"), money(m)
  {  }

  richman(string n) : name(n), money(-1)
  {  }

Първият при инициализиране с някаква сума пари предполага, че притежателят е Angel, а при втория ако инициализираме с някакво име парите стават -1 (няма сведения за неговото богатство).

Идеята за тяхното написване беше да се покаже, че може да има повече от един едноаргументен конструктор, въпреки, че ако са повече могат да се инициализират само по начина в тази програма и третия, разгледан по-долу.

 richman angel(100), peter("Peter");

При опит за инициализация по другия възприет начин

 richman angel = 100, peter = "Peter";  // WRONG !!!

се издава съобщение от компилаторът

Cannot convert 'char *' to 'richman'.

Единствените два начина са най-горе показаният и този по-долу

 richman angel = 100, peter("Peter");

Обърнете внимание, че даже да имате имате само един едноаргументен конструктор и той е от вида на втория (инициализация със стринг), то той не може да се инициализира с равенство

 richman peter = "Peter";  // WRONG !!!

Отново се издава съобщение от компилаторът

Cannot convert 'char *' to 'richman'.

2. Преобразуване на клас на C string до наш клас за стрингове (Converting Strings to xStrings). В лекция 19, т. 6 въведохме наш клас xString, с който да поддържаме стрингове (това беше направено с обучителна цел, защото в същата лекция бе разгледан и класа string, който се поддържа от C++). Сега в тази програма ще въведем конструктор, така както е направено в превъзходния курс на Лафоор [1].

// strcon.cpp
// class models strings; uses constructors
#include <iostream.h>
#include <string.h>             // for strlen(), strcpy(), etc.
#include <conio.h>              // for getch()

const int MAX = 80;             // maximum length of xStrings

class xString
   {
   private:
      char str[MAX];            // ordinary C string
   public:
      xString()                 // no-arg constructor
      {
         strcpy(str, "");       // make null string
      }

      xString(char s[])         // 1-arg constructor
      {
         strcpy(str, s);        // initialize with string
      }

      void input()              // get string from user
      {
         cin.get(str, MAX);
      }

      void display()            // display string
      {
         cout << str;
      }

      void append(xString xs)   // append argument string
      {
         if (strlen(str) + strlen(xs.str) < MAX-1)
           strcat(str, xs.str);
         else
           cout << "\nError: xString too long" << endl;
      }
};

void main()
{
   xString s2, s3;              // make xString objects
   xString s1("Greetings, ");   // make and initialize s1

   cout << "Enter your name: ";
   s2.input();                  // get s2 from user

   s1.append(s2);               // append s2 to s1

   s3 = s1;                     // set s3 to s1

   s3.display();                // display s3

   getch();
}   // main()

В класа xString има два конструктора - един без аргументи и един едноаргументен. Този без аргументи инициализира променливата на класа str с празен стринг "". Това е много полезно, защото ако това не се направи (съзнателно или не), то при отпечатване на str ще излизат случайни символи (това което е в паметта, отделена за променливата, чак до нулевия символ).  И двата конструктора използват функцията strcpy(),  но в едноаргументния конструктор тя копира аргумента s в променливата str.

! Както споменахме в лекция 31, масивите не могат да се инициализират в инициализиращия списък на конструктора, ето защо следващият запис е невалиден код:

  xString(char s[]): str(s[]) // can’t do this -- s is an array
  { }

и компилаторът издава следното съобщение

[C++ Error] Expression syntax.

Аналогично и следният код е грешен

  xString(char s[]): str(s) // WRONG !!!
  { }

Компилаторът издава следното съобщение

 Cannot convert 'char *' to 'char[80]'.
.
3. Превръщане на числени стойности. Това е още един пример, в който се използва едноаргументен конструктор за преобразуване на стойности. Той е взет от курса на Лафоор [1] и поддържа разстояние във футове и инчове.

// englcon.cpp
// demonstrates constructors with English class
#include <iostream.h>
#include <conio.h>              // for getch()

class English                            // English distances
{
   private:
      int feet;
      float inches;

   public:                               // no-argument constructor
      English() : feet(0), inches(0.0)
      {   }

      English(float meters)              // 1-argument constructor
      {
         const float MTF = 3.280839;     // meters to feet
         float fltfeet = MTF * meters;   // get decimal feet
         feet = int(fltfeet);            // integer part is feet
         inches = 12 * (fltfeet-feet);   // remainder is inches
      }

      English(int f, float i) :          // 2-argument constructor
         feet(f), inches(i)
      {   }

      void display()                     // display
      {
         cout << feet << "\'-" << inches << '\"';
      }
};

void main()
{
   English E1(5, 2.5);                  // call 2-arg constructor
   cout << "\nE1 = ";
   E1.display();

   English E2(1.0);                     // call 1-arg constructor
   cout << "\nE2 = ";
   E2.display();

   English E3 = 2;                      // call again 1-arg constructor
   cout << "\nE3 = ";
   E3.display();

   E3 = E2;

   cout << "\nE3 = ";
   E3.display();

   // you can also write
   E3 = 3                               // call again 1-arg constructor

   cout << "\nE3 = ";
   E3.display();

   getch();
}   // main()

Класът English поддържа и работи с разстоянието във футове (променливата feet) и инчове (променливата inches) и има три конструктора - един без аргументи, който нулира разстоянието, един с един аргумент, който ще бъде разгледан по-подробно и един с два аргумента, които представляват футовете и инчовете. Разстояние от 5 фута и 2.5 инча се отбелязва като 5'-2.5".

! На български футовете се наричаха преди стъпки, а за инч преди се използваха думите дюйм от руски или цол от немски. Един фут е равен на 12 инча, а един инч е приблизително равен на 2.54 см. От друга страна един метър е равен на 3.280839 фута.

Едноаргументният конструктор приема разстояние в метри и го преобразува в двете променливи. За целта първо превръща разстоянието във футове, от него взима цялата част, след което намира остатъка му, който умножен по 12 дава инчовете.

В главната функция се създава един обект от класа, E1, който се инициализира с двуаргументния конструктор да е равен на 5'-2.5" и след това се показва на екрана. Създава се и обектът E2, който се иницилизира да е равен на един метър (редът English E2(1.0);), и разстоянието се показва на екрана (резултатът е 3'-3.37007"). След това се създава обектът E2,  който се инициализира да е равен на два метра (редът English E3 = 2;) Обърнете внимание, че това става по друг начин, с оператора за присвояване, а не в скоби - но въпреки това пак е инициализиране. След показване на третия обект (резултатът е 6'-6.74014"), той се приравнява на втория и отново се показва на екрана.

! Обърнете внимание на последното присвояване:

  E3 = 3    // call again 1-arg constructor

Това вече не е инициализация, а присвояване. Отново се извиква едноаргументния конструктор, чийто аргумент е от типа float.

Във функцията display() се използват т.н. специални символи (Escape Characters), част от които бяха разгледани в Таблица 2 на лекция 3. В тази функция, за да се отпечатат на екрана апострофът и кавичките, се поставя преди тях наклонена черта надясно, която е специален символ - "\'-" отпечатва апостроф, а  '\"'отпечатва кавички на екрана.

Не винаги е необходимо такова преобразуване с едноаргументен конструктор и то се прави само при класове, които представят числени величини. В следващите лекции ще покажем още по-прегледен начин за неговото извършване.
.

(съдържание)
.
Литература
.
[1] Robert Lafore; C++ Interactive Course. Waite Group Press, Macmillan Computer Publishing, 1996.
.
Автор: Проф. Процесор Аритметиков
.
[ това е материал от брой 32 от юли 2009 г на списание "Коснос" www.kosnos.com ]

Keywords: С++,  OOP programming , C++ , Classes , Inheritance , Reusability , Creating New Data Types , Polymorphism and Overloading
Ключови думи: клас , обект, обектно ориентирано програмиране , полиморфизъм switch if else ?