Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprenda Herança | Princípios de POO
C# Além do Básico

bookHerança

Você analisou o conceito de classes derivadas na seção anterior. Esse recurso de uma classe herdar propriedades de outra classe é chamado de Herança.

Embora você já conheça o conceito de Herança, desta vez você irá abordá-lo de forma um pouco mais abrangente para compreendê-lo de maneira mais completa.

Como uma revisão rápida, segue um exemplo de Herança:

index.cs

index.cs

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344
#pragma warning disable CS0169 // To disable some unnecessary compiler warnings for this example. Using this is not a recommended practice. using System; class Mammal { int age; float weight; // kilogram (1 kg = 2.2 pounds) } class Dog : Mammal { string breed; public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { Cat myCat = new Cat(); Dog myDog = new Dog(); myCat.speak(); myDog.speak(); } }
Note
Nota

A diretiva #pragma warning disable "warning code" pode ser utilizada para desabilitar determinados avisos do compilador. Geralmente, não é recomendado desabilitar avisos, pois ignorá-los pode causar comportamentos inesperados no programa.

O código acima contém uma classe pai chamada Mammal e duas classes derivadas chamadas Cat e Dog.

Observe que nenhuma das classes possui um construtor explicitamente definido, o que significa que essas classes utilizarão um construtor padrão quando um objeto for criado.

Note
Nota

Um construtor padrão é fornecido automaticamente pela linguagem de programação se uma classe não possuir nenhum construtor explicitamente definido. Um construtor padrão é basicamente um construtor vazio que não contém nenhum código, por exemplo, public className() {} é como um construtor padrão pode ser. Como ele não inicializa nenhum atributo explicitamente, todos os atributos assumem valores padrão - também chamados de valores zero.

Vamos criar manualmente um construtor para a classe Mammal, que inicializa um objeto Mammal com alguns dados:

index.cs

index.cs

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546
#pragma warning disable CS0169 // To disable some unnecessary compiler warnings for this example. Using this is not a recommended practice. using System; class Mammal { int age; float weight; // kg public Mammal(int age, float weight) { this.age = age; this.weight = weight; } } class Dog : Mammal { string breed; public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object with some data Mammal m1 = new Mammal(10, 42.0f); } }

Se você tentar compilar este programa, alguns erros serão exibidos no console. Para compreender esses erros, é necessário primeiro entender dois conceitos importantes relacionados a construtores.

O primeiro é que, uma vez que você define explicitamente um construtor para uma classe, essa classe não possui mais um construtor padrão, e assim o construtor explicitamente definido se torna o principal construtor dessa classe, que neste caso é:

index.cs

index.cs

copy
12345
public Mammal(int age, float weight) { this.age = age; this.weight = weight; }

Portanto, ao criar um novo objeto, é sempre necessário passar os argumentos exigidos pelo construtor na ordem correta:

index.cs

index.cs

copy
1234567
// Incorrect ways to create 'Mammal', will show an error Mammal m1 = new Mammal(); Mammal m1 = new Mammal(10); Mammal m1 = new Mammal(42.0f); // Correct way to create 'Mammal', will execute fine. Mammal m1 = new Mammal(10, 42.0f);

Em segundo lugar, classes derivadas também podem ter construtores; no entanto, antes que o construtor de uma classe derivada seja chamado, o construtor da classe base (pai) também é executado:

index.cs

index.cs

copy
1234567891011121314151617181920212223242526272829303132333435
#pragma warning disable CS0169 // To disable some unnecessary warnings, using this is not a recommended practice. using System; class Mammal { int age; float weight; // kg // No attribute is initialized explicitly in this constructor // Hence, all attributes will take up "zero" values // It is similar to a "default" constructor except it outputs a message public Mammal() { Console.WriteLine("Mammal Constructor Called"); } } class Dog : Mammal { string breed; public Dog() { Console.WriteLine("Dog Constructor Called"); } } class ConsoleApp { static void Main() { Dog myDog = new Dog(); } }

Ao executar este código, observa-se que o método WriteLine() do construtor da classe 'Mammal', que é a classe pai, é chamado automaticamente. Isso significa que é uma regra que o construtor da classe base (também chamado de construtor base) seja sempre chamado antes do construtor da classe derivada.

Essa regra também se aplica em casos de herança multinível:

No diagrama acima, o construtor de Kitten chama o construtor de Cat antes do seu próprio, porém, como Cat também é uma classe derivada, ela chama o construtor de Mammal antes de si mesma, e Mammal chama o construtor de Animal antes do seu próprio construtor. Portanto, no geral, o primeiro construtor a ser executado é o construtor da superclasse — que é o construtor da classe Animal, e a execução segue a partir daí.

Se o construtor da classe pai não recebe nenhum argumento, ele é chamado automaticamente pelo compilador. Por isso, o construtor de 'Mammal' no exemplo acima foi chamado automaticamente. No entanto, vamos analisar novamente o código com erro:

index.cs

index.cs

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243
using System; class Mammal { int age; float weight; // kg public Mammal(int age, float weight) { this.age = age; this.weight = weight; } } class Dog : Mammal { string breed; public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object with some data Mammal m1 = new Mammal(10, 42.0f); } }

No código acima, ocorrem dois erros que basicamente significam que você não chamou manualmente os construtores base — como ele exige alguns argumentos, é necessário chamá-lo manualmente. A sintaxe básica para chamar manualmente o construtor da classe pai é a seguinte:

index.cs

index.cs

copy
12345678910
class DerivedClassName : ParentClassName { // ... attributes // ... methods public DerivedClassName(int arg1, int arg2, ...) : base(arg1, arg2, ...) { // code here } }

Exemplo:

index.cs

index.cs

copy
1234567891011121314151617181920212223242526272829303132
using System; class ExampleParentClass { int value1; int value2; public ExampleParentClass(int value1, int value2) { this.value1 = value1; } } class ExampleDerivedClass : ExampleParentClass { int value3; // The value1 and value2 arguments are passed to the base class's contructor public ExampleDerivedClass(int value1, int value2, int value3) : base (value1, value2) { this.value3 = value3; } } class ConsoleApp { static void Main() { var testObject = new ExampleDerivedClass(5, 7, 9); } }

Usando esta sintaxe, é possível passar todos os dados necessários para o construtor de Mammal através dos construtores de Cat e Dog para corrigir o erro que ocorria anteriormente:

index.cs

index.cs

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
using System; class Mammal { int age; float weight; // kg public Mammal(int age, float weight) { this.age = age; this.weight = weight; } } class Dog : Mammal { string breed; public Dog(int age, float weight, string breed) : base(age, weight) { this.breed = breed; } public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public Cat(int age, float weight, string furPattern) : base(age, weight) { this.furPattern = furPattern; } public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object with some data Mammal m1 = new Mammal(10, 42.0f); // Creating a "Dog" object with some data Dog d1 = new Dog(10, 42.5f, "Dobermann"); Console.WriteLine("Executed Successfully"); } }

Outro recurso importante dos construtores é que eles podem ser sobrecarregados, assim como qualquer outro método pode ser sobrecarga. É possível criar múltiplos construtores com diferentes quantidades de argumentos:

index.cs

index.cs

copy
12345678910111213141516171819202122232425
class Mammal { int age; float weight; // kg // 1st constructor public Mammal() { // We leave it empty for this example // Since it's empty, it mimics the "default" constructor } // 2nd constructor public Mammal(int age) { this.age = age; } // 3rd constructor public Mammal(int age, float weight) { this.age = age; this.weight = weight; } }

Neste caso, a classe Mammal possui 3 construtores. Assim, é possível inicializar ou criar um objeto mammal de 3 maneiras diferentes, e o compilador escolherá qual construtor chamar com base na quantidade e no tipo dos argumentos:

index.cs

index.cs

copy
1234
// All Correct var m1 = new Mammal(); var m2 = new Mammal(10); var m3 = new Mammal(10, 42.5f);

Isso também significa que é possível chamar qualquer um dos 3 construtores a partir dos construtores da classe derivada. Por exemplo, todos estes são válidos:

index.cs

index.cs

copy
123456789101112131415161718
// Using 3rd base constructor public Dog(int age, float weight, string breed) : base(age, weight) { this.breed = breed; } // Using 2nd base constructor public Dog(int age, string breed) : base(age) { this.breed = breed; } // Using 1st base constructor // If the base constructor has no arguments then it is automatically called (similar to the default constructor), so we don't necessarily need to write 'base()' public Dog(string breed) { this.breed = breed; }

Vamos juntar os dois trechos acima e adicionar algumas instruções Console.WriteLine para ver em qual ordem os construtores são executados, observando na prática os resultados:

index.cs

index.cs

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
using System; class Mammal { int age; float weight; // kg // 1st Constructor public Mammal() { // We leave it empty for this example // Since it's empty, it mimics the "default" constructor // The attributes are initialized with zero values Console.WriteLine("Mammal - Constructor 1 Called"); } // 2nd Constructor public Mammal(int age) { this.age = age; Console.WriteLine("Mammal - Constructor 2 Called"); } // 3rd Constructor public Mammal(int age, float weight) { this.age = age; this.weight = weight; Console.WriteLine("Mammal - Constructor 3 Called"); } } class Dog : Mammal { string breed; public Dog() { Console.WriteLine("Dog - Constructor 1 Called"); } // Using 1st Mammal constructor // We don't necessarily need to write 'base()' in this case // It automatically finds and calls the constructor with no arguments public Dog(string breed) { this.breed = breed; Console.WriteLine("Dog - Constructor 2 Called"); } // Using 2nd Mammal constructor public Dog(int age, string breed) : base(age) { this.breed = breed; Console.WriteLine("Dog - Constructor 3 Called"); } // Using 3rd Mammal constructor public Dog(int age, float weight, string breed) : base(age, weight) { this.breed = breed; Console.WriteLine("Dog - Constructor 4 Called"); } public void speak() { Console.WriteLine("Woof!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object using different constructors Mammal m1 = new Mammal(10, 42.0f); Mammal m2 = new Mammal(10); Mammal m3 = new Mammal(); Console.WriteLine("----------"); // Seperator, for ease of reading output // Creating a "Dog" object using different constructors Dog d1 = new Dog(10, 42.0f, "Dobermann"); Console.WriteLine(""); Dog d2 = new Dog(10, "Dobermann"); Console.WriteLine(""); Dog d3 = new Dog("Dobermann"); Console.WriteLine(""); Dog d4 = new Dog(); } }

Agora que você conhece os diferentes recursos da herança, também deve saber como e quando utilizá-los corretamente. A seguir, estão alguns pontos a serem considerados ao pensar em uma estrutura de classes baseada em herança:

Equilíbrio entre simplicidade e flexibilidade: A sobrecarga de construtores permite ter vários construtores diferentes que aceitam diferentes tipos de argumentos, mas o excesso pode tornar o código mais complexo e difícil de manter. É uma boa prática manter o código da classe curto, conciso e conveniente. Evite criar muitos construtores para uma classe, buscando um equilíbrio entre simplicidade e flexibilidade.

Mantenha os construtores simples: Os construtores devem ser responsáveis principalmente por inicializar um objeto com dados básicos. É uma boa prática evitar processamentos desnecessários e lógica complexa dentro de um construtor. Se algum cálculo ou lógica for necessário, é melhor criar um método separado para isso.

;Má prática:;

index.cs

index.cs

copy
123456789101112131415161718192021222324252627
class Customer { string name; string accountType; double balance; public Customer (string name, string accountType, double balance) { this.name = name; this.accountType = accountType; if (accountType == "Savings") { // Plus 1 Percent this.balance = balance + balance * 0.01; } else if (accountType == "HighYieldSavings") { // Plus 5 percent this.balance = balance + balance * 0.05; } else { this.balance = balance; } } }

Boa Prática:

index.cs

index.cs

copy
123456789101112131415161718192021222324252627282930
class Customer { string name; string accountType; double balance; public Customer (string name, string accountType, double balance) { this.name = name; this.accountType = accountType; this.balance = balance; monthlyInterest(); } // This method might be used in other places too private void monthlyInterest() { if(accountType == "Savings") { // Plus 1 Percent balance += balance * 0.01; } else if(accountType == "HighYieldSavings") { // Plus 5 percent balance += balance * 0.05; } } }

Inicializar Atributos Importantes: é necessário inicializar todos os atributos importantes de um objeto com valores corretos para garantir que funcionem corretamente - mesmo que seja um construtor sem argumentos.

Mau Exemplo:

index.cs

index.cs

copy
123456789101112131415
public class Car { private string brand; private string model; private int year; private double price; // Constructor does not initialize important attributes // It is also generally not a good idea to have constructors without any arguments if they're not needed. public Car() { // No initialization of attributes Console.WriteLine("Car Created"); } }

Boa prática:

index.cs

index.cs

copy
123456789101112131415161718192021222324252627282930313233343536373839
public class Car { private string brand; private string model; private int year; private double price; // Good: Constructor initializes important attributes // It also checks if the values are correct // In this case the if-else statements are not unnecessary since they are important for ensuring that the object functions correctly. public Car(string brand, string model, int year, double price) { this.brand = brand; this.model = model; // Validate and set the year // The first public car was created in 1886 :) if (year > 1886) { this.year = year; } else { Console.WriteLine("Invalid year. Setting year to default."); this.year = DateTime.Now.Year; // Set to current year as default } // Validate and set the price if (price >= 0) { this.price = price; } else { Console.WriteLine("Invalid price. Setting price to default."); this.price = 0; // Set to a default value } } }

1. Qual recurso permite criar múltiplos construtores para uma classe?

2. Pode ser necessário utilizar um dos conceitos das seções anteriores neste quiz. O código abaixo apresenta um erro nas linhas 15 e 16. Analise o código cuidadosamente e decida qual é a correção mais eficiente para esse erro:

question mark

Qual recurso permite criar múltiplos construtores para uma classe?

Select the correct answer

question mark

Pode ser necessário utilizar um dos conceitos das seções anteriores neste quiz. O código abaixo apresenta um erro nas linhas 15 e 16. Analise o código cuidadosamente e decida qual é a correção mais eficiente para esse erro:

Select the correct answer

Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 5. Capítulo 2

Pergunte à IA

expand

Pergunte à IA

ChatGPT

Pergunte o que quiser ou experimente uma das perguntas sugeridas para iniciar nosso bate-papo

Awesome!

Completion rate improved to 2.04

bookHerança

Deslize para mostrar o menu

Você analisou o conceito de classes derivadas na seção anterior. Esse recurso de uma classe herdar propriedades de outra classe é chamado de Herança.

Embora você já conheça o conceito de Herança, desta vez você irá abordá-lo de forma um pouco mais abrangente para compreendê-lo de maneira mais completa.

Como uma revisão rápida, segue um exemplo de Herança:

index.cs

index.cs

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344
#pragma warning disable CS0169 // To disable some unnecessary compiler warnings for this example. Using this is not a recommended practice. using System; class Mammal { int age; float weight; // kilogram (1 kg = 2.2 pounds) } class Dog : Mammal { string breed; public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { Cat myCat = new Cat(); Dog myDog = new Dog(); myCat.speak(); myDog.speak(); } }
Note
Nota

A diretiva #pragma warning disable "warning code" pode ser utilizada para desabilitar determinados avisos do compilador. Geralmente, não é recomendado desabilitar avisos, pois ignorá-los pode causar comportamentos inesperados no programa.

O código acima contém uma classe pai chamada Mammal e duas classes derivadas chamadas Cat e Dog.

Observe que nenhuma das classes possui um construtor explicitamente definido, o que significa que essas classes utilizarão um construtor padrão quando um objeto for criado.

Note
Nota

Um construtor padrão é fornecido automaticamente pela linguagem de programação se uma classe não possuir nenhum construtor explicitamente definido. Um construtor padrão é basicamente um construtor vazio que não contém nenhum código, por exemplo, public className() {} é como um construtor padrão pode ser. Como ele não inicializa nenhum atributo explicitamente, todos os atributos assumem valores padrão - também chamados de valores zero.

Vamos criar manualmente um construtor para a classe Mammal, que inicializa um objeto Mammal com alguns dados:

index.cs

index.cs

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546
#pragma warning disable CS0169 // To disable some unnecessary compiler warnings for this example. Using this is not a recommended practice. using System; class Mammal { int age; float weight; // kg public Mammal(int age, float weight) { this.age = age; this.weight = weight; } } class Dog : Mammal { string breed; public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object with some data Mammal m1 = new Mammal(10, 42.0f); } }

Se você tentar compilar este programa, alguns erros serão exibidos no console. Para compreender esses erros, é necessário primeiro entender dois conceitos importantes relacionados a construtores.

O primeiro é que, uma vez que você define explicitamente um construtor para uma classe, essa classe não possui mais um construtor padrão, e assim o construtor explicitamente definido se torna o principal construtor dessa classe, que neste caso é:

index.cs

index.cs

copy
12345
public Mammal(int age, float weight) { this.age = age; this.weight = weight; }

Portanto, ao criar um novo objeto, é sempre necessário passar os argumentos exigidos pelo construtor na ordem correta:

index.cs

index.cs

copy
1234567
// Incorrect ways to create 'Mammal', will show an error Mammal m1 = new Mammal(); Mammal m1 = new Mammal(10); Mammal m1 = new Mammal(42.0f); // Correct way to create 'Mammal', will execute fine. Mammal m1 = new Mammal(10, 42.0f);

Em segundo lugar, classes derivadas também podem ter construtores; no entanto, antes que o construtor de uma classe derivada seja chamado, o construtor da classe base (pai) também é executado:

index.cs

index.cs

copy
1234567891011121314151617181920212223242526272829303132333435
#pragma warning disable CS0169 // To disable some unnecessary warnings, using this is not a recommended practice. using System; class Mammal { int age; float weight; // kg // No attribute is initialized explicitly in this constructor // Hence, all attributes will take up "zero" values // It is similar to a "default" constructor except it outputs a message public Mammal() { Console.WriteLine("Mammal Constructor Called"); } } class Dog : Mammal { string breed; public Dog() { Console.WriteLine("Dog Constructor Called"); } } class ConsoleApp { static void Main() { Dog myDog = new Dog(); } }

Ao executar este código, observa-se que o método WriteLine() do construtor da classe 'Mammal', que é a classe pai, é chamado automaticamente. Isso significa que é uma regra que o construtor da classe base (também chamado de construtor base) seja sempre chamado antes do construtor da classe derivada.

Essa regra também se aplica em casos de herança multinível:

No diagrama acima, o construtor de Kitten chama o construtor de Cat antes do seu próprio, porém, como Cat também é uma classe derivada, ela chama o construtor de Mammal antes de si mesma, e Mammal chama o construtor de Animal antes do seu próprio construtor. Portanto, no geral, o primeiro construtor a ser executado é o construtor da superclasse — que é o construtor da classe Animal, e a execução segue a partir daí.

Se o construtor da classe pai não recebe nenhum argumento, ele é chamado automaticamente pelo compilador. Por isso, o construtor de 'Mammal' no exemplo acima foi chamado automaticamente. No entanto, vamos analisar novamente o código com erro:

index.cs

index.cs

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243
using System; class Mammal { int age; float weight; // kg public Mammal(int age, float weight) { this.age = age; this.weight = weight; } } class Dog : Mammal { string breed; public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object with some data Mammal m1 = new Mammal(10, 42.0f); } }

No código acima, ocorrem dois erros que basicamente significam que você não chamou manualmente os construtores base — como ele exige alguns argumentos, é necessário chamá-lo manualmente. A sintaxe básica para chamar manualmente o construtor da classe pai é a seguinte:

index.cs

index.cs

copy
12345678910
class DerivedClassName : ParentClassName { // ... attributes // ... methods public DerivedClassName(int arg1, int arg2, ...) : base(arg1, arg2, ...) { // code here } }

Exemplo:

index.cs

index.cs

copy
1234567891011121314151617181920212223242526272829303132
using System; class ExampleParentClass { int value1; int value2; public ExampleParentClass(int value1, int value2) { this.value1 = value1; } } class ExampleDerivedClass : ExampleParentClass { int value3; // The value1 and value2 arguments are passed to the base class's contructor public ExampleDerivedClass(int value1, int value2, int value3) : base (value1, value2) { this.value3 = value3; } } class ConsoleApp { static void Main() { var testObject = new ExampleDerivedClass(5, 7, 9); } }

Usando esta sintaxe, é possível passar todos os dados necessários para o construtor de Mammal através dos construtores de Cat e Dog para corrigir o erro que ocorria anteriormente:

index.cs

index.cs

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
using System; class Mammal { int age; float weight; // kg public Mammal(int age, float weight) { this.age = age; this.weight = weight; } } class Dog : Mammal { string breed; public Dog(int age, float weight, string breed) : base(age, weight) { this.breed = breed; } public void speak() { Console.WriteLine("Woof!"); } } class Cat : Mammal { string furPattern; public Cat(int age, float weight, string furPattern) : base(age, weight) { this.furPattern = furPattern; } public void speak() { Console.WriteLine("Meow!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object with some data Mammal m1 = new Mammal(10, 42.0f); // Creating a "Dog" object with some data Dog d1 = new Dog(10, 42.5f, "Dobermann"); Console.WriteLine("Executed Successfully"); } }

Outro recurso importante dos construtores é que eles podem ser sobrecarregados, assim como qualquer outro método pode ser sobrecarga. É possível criar múltiplos construtores com diferentes quantidades de argumentos:

index.cs

index.cs

copy
12345678910111213141516171819202122232425
class Mammal { int age; float weight; // kg // 1st constructor public Mammal() { // We leave it empty for this example // Since it's empty, it mimics the "default" constructor } // 2nd constructor public Mammal(int age) { this.age = age; } // 3rd constructor public Mammal(int age, float weight) { this.age = age; this.weight = weight; } }

Neste caso, a classe Mammal possui 3 construtores. Assim, é possível inicializar ou criar um objeto mammal de 3 maneiras diferentes, e o compilador escolherá qual construtor chamar com base na quantidade e no tipo dos argumentos:

index.cs

index.cs

copy
1234
// All Correct var m1 = new Mammal(); var m2 = new Mammal(10); var m3 = new Mammal(10, 42.5f);

Isso também significa que é possível chamar qualquer um dos 3 construtores a partir dos construtores da classe derivada. Por exemplo, todos estes são válidos:

index.cs

index.cs

copy
123456789101112131415161718
// Using 3rd base constructor public Dog(int age, float weight, string breed) : base(age, weight) { this.breed = breed; } // Using 2nd base constructor public Dog(int age, string breed) : base(age) { this.breed = breed; } // Using 1st base constructor // If the base constructor has no arguments then it is automatically called (similar to the default constructor), so we don't necessarily need to write 'base()' public Dog(string breed) { this.breed = breed; }

Vamos juntar os dois trechos acima e adicionar algumas instruções Console.WriteLine para ver em qual ordem os construtores são executados, observando na prática os resultados:

index.cs

index.cs

copy
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
using System; class Mammal { int age; float weight; // kg // 1st Constructor public Mammal() { // We leave it empty for this example // Since it's empty, it mimics the "default" constructor // The attributes are initialized with zero values Console.WriteLine("Mammal - Constructor 1 Called"); } // 2nd Constructor public Mammal(int age) { this.age = age; Console.WriteLine("Mammal - Constructor 2 Called"); } // 3rd Constructor public Mammal(int age, float weight) { this.age = age; this.weight = weight; Console.WriteLine("Mammal - Constructor 3 Called"); } } class Dog : Mammal { string breed; public Dog() { Console.WriteLine("Dog - Constructor 1 Called"); } // Using 1st Mammal constructor // We don't necessarily need to write 'base()' in this case // It automatically finds and calls the constructor with no arguments public Dog(string breed) { this.breed = breed; Console.WriteLine("Dog - Constructor 2 Called"); } // Using 2nd Mammal constructor public Dog(int age, string breed) : base(age) { this.breed = breed; Console.WriteLine("Dog - Constructor 3 Called"); } // Using 3rd Mammal constructor public Dog(int age, float weight, string breed) : base(age, weight) { this.breed = breed; Console.WriteLine("Dog - Constructor 4 Called"); } public void speak() { Console.WriteLine("Woof!"); } } class ConsoleApp { static void Main() { // Creating a "Mammal" object using different constructors Mammal m1 = new Mammal(10, 42.0f); Mammal m2 = new Mammal(10); Mammal m3 = new Mammal(); Console.WriteLine("----------"); // Seperator, for ease of reading output // Creating a "Dog" object using different constructors Dog d1 = new Dog(10, 42.0f, "Dobermann"); Console.WriteLine(""); Dog d2 = new Dog(10, "Dobermann"); Console.WriteLine(""); Dog d3 = new Dog("Dobermann"); Console.WriteLine(""); Dog d4 = new Dog(); } }

Agora que você conhece os diferentes recursos da herança, também deve saber como e quando utilizá-los corretamente. A seguir, estão alguns pontos a serem considerados ao pensar em uma estrutura de classes baseada em herança:

Equilíbrio entre simplicidade e flexibilidade: A sobrecarga de construtores permite ter vários construtores diferentes que aceitam diferentes tipos de argumentos, mas o excesso pode tornar o código mais complexo e difícil de manter. É uma boa prática manter o código da classe curto, conciso e conveniente. Evite criar muitos construtores para uma classe, buscando um equilíbrio entre simplicidade e flexibilidade.

Mantenha os construtores simples: Os construtores devem ser responsáveis principalmente por inicializar um objeto com dados básicos. É uma boa prática evitar processamentos desnecessários e lógica complexa dentro de um construtor. Se algum cálculo ou lógica for necessário, é melhor criar um método separado para isso.

;Má prática:;

index.cs

index.cs

copy
123456789101112131415161718192021222324252627
class Customer { string name; string accountType; double balance; public Customer (string name, string accountType, double balance) { this.name = name; this.accountType = accountType; if (accountType == "Savings") { // Plus 1 Percent this.balance = balance + balance * 0.01; } else if (accountType == "HighYieldSavings") { // Plus 5 percent this.balance = balance + balance * 0.05; } else { this.balance = balance; } } }

Boa Prática:

index.cs

index.cs

copy
123456789101112131415161718192021222324252627282930
class Customer { string name; string accountType; double balance; public Customer (string name, string accountType, double balance) { this.name = name; this.accountType = accountType; this.balance = balance; monthlyInterest(); } // This method might be used in other places too private void monthlyInterest() { if(accountType == "Savings") { // Plus 1 Percent balance += balance * 0.01; } else if(accountType == "HighYieldSavings") { // Plus 5 percent balance += balance * 0.05; } } }

Inicializar Atributos Importantes: é necessário inicializar todos os atributos importantes de um objeto com valores corretos para garantir que funcionem corretamente - mesmo que seja um construtor sem argumentos.

Mau Exemplo:

index.cs

index.cs

copy
123456789101112131415
public class Car { private string brand; private string model; private int year; private double price; // Constructor does not initialize important attributes // It is also generally not a good idea to have constructors without any arguments if they're not needed. public Car() { // No initialization of attributes Console.WriteLine("Car Created"); } }

Boa prática:

index.cs

index.cs

copy
123456789101112131415161718192021222324252627282930313233343536373839
public class Car { private string brand; private string model; private int year; private double price; // Good: Constructor initializes important attributes // It also checks if the values are correct // In this case the if-else statements are not unnecessary since they are important for ensuring that the object functions correctly. public Car(string brand, string model, int year, double price) { this.brand = brand; this.model = model; // Validate and set the year // The first public car was created in 1886 :) if (year > 1886) { this.year = year; } else { Console.WriteLine("Invalid year. Setting year to default."); this.year = DateTime.Now.Year; // Set to current year as default } // Validate and set the price if (price >= 0) { this.price = price; } else { Console.WriteLine("Invalid price. Setting price to default."); this.price = 0; // Set to a default value } } }

1. Qual recurso permite criar múltiplos construtores para uma classe?

2. Pode ser necessário utilizar um dos conceitos das seções anteriores neste quiz. O código abaixo apresenta um erro nas linhas 15 e 16. Analise o código cuidadosamente e decida qual é a correção mais eficiente para esse erro:

question mark

Qual recurso permite criar múltiplos construtores para uma classe?

Select the correct answer

question mark

Pode ser necessário utilizar um dos conceitos das seções anteriores neste quiz. O código abaixo apresenta um erro nas linhas 15 e 16. Analise o código cuidadosamente e decida qual é a correção mais eficiente para esse erro:

Select the correct answer

Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 5. Capítulo 2
some-alt